iOS drag on UIView, cloth effect
Asked Answered
H

2

21

Since I saw this menu drag concept, I have really been interested to find out how to accomplish it. So I am wondering how I would go about dragging with a cloth-effect in a UIView?

I know how to drag items, but how do you give them the ripple effect?

(Better image: http://dribbble.com/shots/899177-Slide-Concept/attachments/98219) enter image description here

Hazem answered 10/12, 2013 at 21:2 Comment(10)
I'm pretty curious how the creator of this image created it, if we can replicate those steps from what he did and what the software he used did to this image, we might achieve this effectConcertante
github.com/honcheng/PaperFold-for-iOSDerogate
@BrightFuture since it is on dribble, I am very certain he is a designer and designed it in photoshop. Hence it is not a screenshot.Hazem
@PaulPeelen that's the point, if we know how photoshop does this effect, we can do this in our appsConcertante
@MikeAlter thanks for the tip, but unfortunately that is nowhere close to any resemblance of the image attached. A folding view is not that hard to make, it's the cloth effect I wish to learn about how to make.Hazem
@BrightFuture ah, true. You are right, there can be some good value in it. I'll see if I can reach out to the designer and ask him.Hazem
I don't have time to try and make it now but I'd use SceneKit. Why? SceneKit can be overlaid onto of UIKit just by setting the backgroundColor to clear. It can use UIView(or CALayer's I forget) as the texture on geometry. Then create a plane with lots of subdivisions and morph the geometry based on the users finger position. Still a lot of work, but at least the rendering side is handled for you.Carrolcarroll
@KyleHowells that sounds interesting. I'll try to set aside some time to try that out. Never did anything with Scenekit. Thanks for the tipHazem
@PaulPeelen I remembered finding an implementation of this Dribbble years ago but couldn't find it (hence my comment). I just stumbled on it this evening and have posted the details about it and roughly how it works as an answer.Carrolcarroll
@KyleHowells funny enough I was reading that blog post earlier this evening and looked very promising. I do think it is the solution to my question and giving the short time left on the bounty I will therefor accept it. Thank you!Hazem
C
2

There is an open source reimplementation of this already.

This blog post: Mesh Transforms covers the private CAMeshTransform. Rather than treating a CALayer as a simple quad, it allows CALayers to be turned into a mesh of connected faces. This class is how Apple has been able to implement the page curl and iBooks page turning effects.

However, the API doesn't tolerate malformed input at all well and Apple has kept it a private API.

If you keep reading that blog post though you'll come to this section just after the bit about it being private API.

In the spirit of CAMeshTransform I created a BCMeshTransform which copies almost every feature of the original class.
...
Without direct, public access to Core Animation render server I was forced to use OpenGL for my implementation. This is not a perfect solution as it introduces some drawbacks the original class didn’t have, but it seems to be the only currently available option.

In effect he renders the content view into an OpenGL texture and then displays that. This lets him mess around with it however he likes.

Including like this...

I encourage you to check out the demo app I made for BCMeshTransformView. It contains a few ideas of how a mesh transform can be used to enrich interaction, like my very simple, but functional take on that famous Dribbble.

What famous Dribbble? This one:

Here is what the example looks like:

Open source project: https://github.com/Ciechan/BCMeshTransformView
Example Implementation of the curtain effect: BCCurtainDemoViewController.m


How does it work?

It sets the BCMeshTransformView up with some lighting and perspective.

// From: https://github.com/Ciechan/BCMeshTransformView/blob/master/Demo/BCMeshTransformViewDemo/BCCurtainDemoViewController.m#L59
self.transformView.diffuseLightFactor = 0.5;

CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0/2000.0;
self.transformView.supplementaryTransform = perspective;

Then using a UIPanGestureRecognizer it tracks the touches and uses this method to build a new mesh transform every time the users finger moves.

// From: https://github.com/Ciechan/BCMeshTransformView/blob/master/Demo/BCMeshTransformViewDemo/BCCurtainDemoViewController.m#L91
self.transformView.meshTransform = [BCMutableMeshTransform curtainMeshTransformAtPoint:CGPointMake(point.x + self.surplus, point.y) boundsSize:self.transformView.bounds.size];

// From: https://github.com/Ciechan/BCMeshTransformView/blob/master/Demo/BCMeshTransformViewDemo/BCMeshTransform%2BDemoTransforms.m#L14
+ (instancetype)curtainMeshTransformAtPoint:(CGPoint)point boundsSize:(CGSize)boundsSize
{
    const float Frills = 3;

    point.x = MIN(point.x, boundsSize.width);

    BCMutableMeshTransform *transform = [BCMutableMeshTransform identityMeshTransformWithNumberOfRows:20 numberOfColumns:50];

    CGPoint np = CGPointMake(point.x/boundsSize.width, point.y/boundsSize.height);

    [transform mapVerticesUsingBlock:^BCMeshVertex(BCMeshVertex vertex, NSUInteger vertexIndex) {
        float dy = vertex.to.y - np.y;
        float bend = 0.25f * (1.0f - expf(-dy * dy * 10.0f));

        float x = vertex.to.x;

        vertex.to.z = 0.1 + 0.1f * sin(-1.4f * cos(x * x * Frills * 2.0 * M_PI)) * (1.0 - np.x);
        vertex.to.x = (vertex.to.x) * np.x + vertex.to.x * bend * (1.0 - np.x);

        return vertex;
    }];

    return transform;
}
Carrolcarroll answered 26/2, 2017 at 20:58 Comment(0)
F
9

In short: it’s really, really hard. The old Classics app achieved something along those lines using a series of pre-rendered smooth paper images under a simple transform of their view content, but as you can see from those screenshots (and the one below—note that the text at the bottom is still making a straight line, since it’s getting a basic perspective transform), the effect was fairly limited.

screenshot of Classics app showing page-turn effect

The effect shown in that Dribbble design is much more complicated, since it’s actually doing a scrunching-up warp of the view’s content, not just skewing it as Classics did; the only way I can think of to do that exact effect on iOS at present would be to drop into OpenGL and distort the content with a mesh there.

A simpler option would be to use UIPageViewController, which will at least you the nice iBooks-style curling paper effect—it ain’t fabric, but it’s a lot easier than the GL option.

Florrieflorry answered 10/12, 2013 at 22:5 Comment(4)
Thank you for your answer. Seems I need to learn how to do it in OpenGL. I guess this will be a long-time home project for me =)Hazem
@PaulPeelen - If you want a place to start, GPU Pro 2 has a chapter where they use OpenGL ES to replicate an actual page turning. The source code for the book can be found here: crcpress.com/product/isbn/9781568817187 and I could see how you might be able to modify the page mesh to crinkle instead of turning. Your UIView could be rendered to a texture to map onto that mesh.Fipple
You could possibly do something with CoreImage too. Render the view into a UIImage and then apply effects on the image. With the right combination of distortion effects you might be able to replicate your required effect.Tomb
Another place to look with an OpenGL sample of a ripple is Apple's GLCameraRipple project. It creates a water ripple in a live camera view as your drag your finger across the screen. developer.apple.com/library/content/samplecode/GLCameraRipple/…Checkpoint
C
2

There is an open source reimplementation of this already.

This blog post: Mesh Transforms covers the private CAMeshTransform. Rather than treating a CALayer as a simple quad, it allows CALayers to be turned into a mesh of connected faces. This class is how Apple has been able to implement the page curl and iBooks page turning effects.

However, the API doesn't tolerate malformed input at all well and Apple has kept it a private API.

If you keep reading that blog post though you'll come to this section just after the bit about it being private API.

In the spirit of CAMeshTransform I created a BCMeshTransform which copies almost every feature of the original class.
...
Without direct, public access to Core Animation render server I was forced to use OpenGL for my implementation. This is not a perfect solution as it introduces some drawbacks the original class didn’t have, but it seems to be the only currently available option.

In effect he renders the content view into an OpenGL texture and then displays that. This lets him mess around with it however he likes.

Including like this...

I encourage you to check out the demo app I made for BCMeshTransformView. It contains a few ideas of how a mesh transform can be used to enrich interaction, like my very simple, but functional take on that famous Dribbble.

What famous Dribbble? This one:

Here is what the example looks like:

Open source project: https://github.com/Ciechan/BCMeshTransformView
Example Implementation of the curtain effect: BCCurtainDemoViewController.m


How does it work?

It sets the BCMeshTransformView up with some lighting and perspective.

// From: https://github.com/Ciechan/BCMeshTransformView/blob/master/Demo/BCMeshTransformViewDemo/BCCurtainDemoViewController.m#L59
self.transformView.diffuseLightFactor = 0.5;

CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0/2000.0;
self.transformView.supplementaryTransform = perspective;

Then using a UIPanGestureRecognizer it tracks the touches and uses this method to build a new mesh transform every time the users finger moves.

// From: https://github.com/Ciechan/BCMeshTransformView/blob/master/Demo/BCMeshTransformViewDemo/BCCurtainDemoViewController.m#L91
self.transformView.meshTransform = [BCMutableMeshTransform curtainMeshTransformAtPoint:CGPointMake(point.x + self.surplus, point.y) boundsSize:self.transformView.bounds.size];

// From: https://github.com/Ciechan/BCMeshTransformView/blob/master/Demo/BCMeshTransformViewDemo/BCMeshTransform%2BDemoTransforms.m#L14
+ (instancetype)curtainMeshTransformAtPoint:(CGPoint)point boundsSize:(CGSize)boundsSize
{
    const float Frills = 3;

    point.x = MIN(point.x, boundsSize.width);

    BCMutableMeshTransform *transform = [BCMutableMeshTransform identityMeshTransformWithNumberOfRows:20 numberOfColumns:50];

    CGPoint np = CGPointMake(point.x/boundsSize.width, point.y/boundsSize.height);

    [transform mapVerticesUsingBlock:^BCMeshVertex(BCMeshVertex vertex, NSUInteger vertexIndex) {
        float dy = vertex.to.y - np.y;
        float bend = 0.25f * (1.0f - expf(-dy * dy * 10.0f));

        float x = vertex.to.x;

        vertex.to.z = 0.1 + 0.1f * sin(-1.4f * cos(x * x * Frills * 2.0 * M_PI)) * (1.0 - np.x);
        vertex.to.x = (vertex.to.x) * np.x + vertex.to.x * bend * (1.0 - np.x);

        return vertex;
    }];

    return transform;
}
Carrolcarroll answered 26/2, 2017 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.