开发者

How can i make an image to rotate based on the direction of my finger swipe

开发者 https://www.devze.com 2023-01-17 11:12 出处:网络
I\'m trying to spin an circle image based on user swipe.Now I\'ve done by considering the as two parts. one is the left side and other is the right side.

I'm trying to spin an circle image based on user swipe.Now I've done by considering the as two parts. one is the left side and other is the right side. If the user swipes down from right half m开发者_运维知识库eans it rotates clockwise and swipe up means anti clock wise. In left side I've done the vice versa. So now my image will rotate fine only when I touch the left and right half.. on touching top and bottom .. its behaving differently. I've even tried ny calculating the radians.. its also not working Can any one suggest me to identify clockwise or anticlock wise in a better way...

Thank u, Lakshmi jones


You should approach this problem with trignometry. Assuming you know the starting point of swipe (a1,b1) and the ending point of swipe (a2,b2) The circles centre is at (x,y)

How can i make an image to rotate based on the direction of my finger swipe

If we know the difference of angles made by lines (x,y)->(a1,b1) and (x,y)->(a2,b2) we will know whether to rotate clockwise or anticlockwise based on whether the above said angle is positive or negative.

Angle made by a line is calculated below. Let the red angle be red

if(a1-x==0){
    if(b1-y>0) red=pi/2
    else red = 3*pi/2
}
else{
  tan(red) = abs((b1-y)/(a1-x))
  red = tan-inverse( abs((b1-y)/(a1-x)) )
  if(a1-x<0){
    if(b1-y<=0)
        red+=pi;
    else
        red+=pi/2
  }
  else if(a1-x>0 && b1-y<0){
      red+=3*pi/2
  }
}

See here to know how to calculate tan-inverse.

Similarly calculate the value of angle green. After doing that just comparing the value of green and red will let you know what to do.

if(red - green == pi || red - green == 0){
    do_nothing();        
}else if(red - green > 0){
    rotate_clockwise();        
}else{
    rotate_anticlockwise();
}

By using the acceleration/velocity data of the swipe you could rotate the circle with the same acceleration/velocity.


Have you ever tried this tutorial for your problem. This will help you for sure.

The .h file for calculating the swipe

#import <UIKit/UIKit.h>
#import "SMRotaryProtocol.h"

@interface SMRotaryWheel : UIControl

@property (weak) id <SMRotaryProtocol> delegate;
@property (nonatomic, strong) UIView *container;
@property int numberOfSections;
@property CGAffineTransform startTransform;
@property (nonatomic, strong) NSMutableArray *cloves;
@property int currentValue;


- (id) initWithFrame:(CGRect)frame andDelegate:(id)del withSections:(int)sectionsNumber;

And the .m file is

#import "SMRotaryWheel.h"
#import <QuartzCore/QuartzCore.h>
#import "SMCLove.h"

@interface SMRotaryWheel()
    - (void)drawWheel;
    - (float) calculateDistanceFromCenter:(CGPoint)point;
    - (void) buildClovesEven;
    - (void) buildClovesOdd;
    - (UIImageView *) getCloveByValue:(int)value;
    - (NSString *) getCloveName:(int)position;
@end

static float deltaAngle;
static float minAlphavalue = 0.6;
static float maxAlphavalue = 1.0;

@implementation SMRotaryWheel

@synthesize delegate, container, numberOfSections, startTransform, cloves, currentValue;


- (id) initWithFrame:(CGRect)frame andDelegate:(id)del withSections:(int)sectionsNumber {

    if ((self = [super initWithFrame:frame])) {

        self.currentValue = 0;
        self.numberOfSections = sectionsNumber;
        self.delegate = del;
        [self drawWheel];

    }
    return self;
}



- (void) drawWheel {

    container = [[UIView alloc] initWithFrame:self.frame];

    CGFloat angleSize = 2*M_PI/numberOfSections;

    for (int i = 0; i < numberOfSections; i++) {

        UIImageView *im = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"segment.png"]];

        im.layer.anchorPoint = CGPointMake(1.0f, 0.5f);
        im.layer.position = CGPointMake(container.bounds.size.width/2.0-container.frame.origin.x, 
                                        container.bounds.size.height/2.0-container.frame.origin.y); 
        im.transform = CGAffineTransformMakeRotation(angleSize*i);
        im.alpha = minAlphavalue;
        im.tag = i;

        if (i == 0) {
            im.alpha = maxAlphavalue;
        }

        UIImageView *cloveImage = [[UIImageView alloc] initWithFrame:CGRectMake(12, 15, 40, 40)];
        cloveImage.image = [UIImage imageNamed:[NSString stringWithFormat:@"icon%i.png", i]];
        [im addSubview:cloveImage];

        [container addSubview:im];

    }

    container.userInteractionEnabled = NO;
    [self addSubview:container];

    cloves = [NSMutableArray arrayWithCapacity:numberOfSections];

    UIImageView *bg = [[UIImageView alloc] initWithFrame:self.frame];
    bg.image = [UIImage imageNamed:@"bg.png"];
    [self addSubview:bg];

    UIImageView *mask = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 58, 58)];
    mask.image =[UIImage imageNamed:@"centerButton.png"] ;
    mask.center = self.center;
    mask.center = CGPointMake(mask.center.x, mask.center.y+3);
    [self addSubview:mask];

    if (numberOfSections % 2 == 0) {

        [self buildClovesEven];

    } else {

        [self buildClovesOdd];

    }

    [self.delegate wheelDidChangeValue:[self getCloveName:currentValue]];


}


- (UIImageView *) getCloveByValue:(int)value {

    UIImageView *res;

    NSArray *views = [container subviews];

    for (UIImageView *im in views) {

        if (im.tag == value)
            res = im;

    }

    return res;

}

- (void) buildClovesEven {

    CGFloat fanWidth = M_PI*2/numberOfSections;
    CGFloat mid = 0;

    for (int i = 0; i < numberOfSections; i++) {

        SMClove *clove = [[SMClove alloc] init];
        clove.midValue = mid;
        clove.minValue = mid - (fanWidth/2);
        clove.maxValue = mid + (fanWidth/2);
        clove.value = i;


        if (clove.maxValue-fanWidth < - M_PI) {

            mid = M_PI;
            clove.midValue = mid;
            clove.minValue = fabsf(clove.maxValue);

        }

        mid -= fanWidth;


        NSLog(@"cl is %@", clove);

        [cloves addObject:clove];

    }

}


- (void) buildClovesOdd {

    CGFloat fanWidth = M_PI*2/numberOfSections;
    CGFloat mid = 0;

    for (int i = 0; i < numberOfSections; i++) {

        SMClove *clove = [[SMClove alloc] init];
        clove.midValue = mid;
        clove.minValue = mid - (fanWidth/2);
        clove.maxValue = mid + (fanWidth/2);
        clove.value = i;

        mid -= fanWidth;

        if (clove.minValue < - M_PI) {

            mid = -mid;
            mid -= fanWidth; 

        }


        [cloves addObject:clove];

        NSLog(@"cl is %@", clove);

    }

}

- (float) calculateDistanceFromCenter:(CGPoint)point {

    CGPoint center = CGPointMake(self.bounds.size.width/2.0f, self.bounds.size.height/2.0f);
    float dx = point.x - center.x;
    float dy = point.y - center.y;
    return sqrt(dx*dx + dy*dy);

}

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {

    CGPoint touchPoint = [touch locationInView:self];
    float dist = [self calculateDistanceFromCenter:touchPoint];

    if (dist < 40 || dist > 100) 
    {
        // forcing a tap to be on the ferrule
        NSLog(@"ignoring tap (%f,%f)", touchPoint.x, touchPoint.y);
        return NO;
    }

    float dx = touchPoint.x - container.center.x;
    float dy = touchPoint.y - container.center.y;
    deltaAngle = atan2(dy,dx); 

    startTransform = container.transform;

    UIImageView *im = [self getCloveByValue:currentValue];
    im.alpha = minAlphavalue;

    return YES;

}

- (BOOL)continueTrackingWithTouch:(UITouch*)touch withEvent:(UIEvent*)event
{

    CGPoint pt = [touch locationInView:self];

    float dist = [self calculateDistanceFromCenter:pt];

    if (dist < 40 || dist > 100) 
    {
        // a drag path too close to the center
        NSLog(@"drag path too close to the center (%f,%f)", pt.x, pt.y);

        // here you might want to implement your solution when the drag 
        // is too close to the center
        // You might go back to the clove previously selected
        // or you might calculate the clove corresponding to
        // the "exit point" of the drag.

    }

    float dx = pt.x  - container.center.x;
    float dy = pt.y  - container.center.y;
    float ang = atan2(dy,dx);

    float angleDifference = deltaAngle - ang;

    container.transform = CGAffineTransformRotate(startTransform, -angleDifference);

    return YES;

}

- (void)endTrackingWithTouch:(UITouch*)touch withEvent:(UIEvent*)event
{

    CGFloat radians = atan2f(container.transform.b, container.transform.a);

    CGFloat newVal = 0.0;

    for (SMClove *c in cloves) {

        if (c.minValue > 0 && c.maxValue < 0) { // anomalous case

            if (c.maxValue > radians || c.minValue < radians) {

                if (radians > 0) { // we are in the positive quadrant

                    newVal = radians - M_PI;

                } else { // we are in the negative one

                    newVal = M_PI + radians;                    

                }
                currentValue = c.value;

            }

        }

        else if (radians > c.minValue && radians < c.maxValue) {

            newVal = radians - c.midValue;
            currentValue = c.value;

        }

    }

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.2];

    CGAffineTransform t = CGAffineTransformRotate(container.transform, -newVal);
    container.transform = t;

    [UIView commitAnimations];

    [self.delegate wheelDidChangeValue:[self getCloveName:currentValue]];

    UIImageView *im = [self getCloveByValue:currentValue];
    im.alpha = maxAlphavalue;

}

- (NSString *) getCloveName:(int)position {

    NSString *res = @"";

    switch (position) {
        case 0:
            res = @"Circles";
            break;

        case 1:
            res = @"Flower";
            break;

        case 2:
            res = @"Monster";
            break;

        case 3:
            res = @"Person";
            break;

        case 4:
            res = @"Smile";
            break;

        case 5:
            res = @"Sun";
            break;

        case 6:
            res = @"Swirl";
            break;

        case 7:
            res = @"3 circles";
            break;

        case 8:
            res = @"Triangle";
            break;

        default:
            break;
    }

    return res;
}



@end

Main Methods which will help you to track the swipe are

- (float) calculateDistanceFromCenter:(CGPoint)point

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event

- (BOOL)continueTrackingWithTouch:(UITouch*)touch withEvent:(UIEvent*)event

- (void)endTrackingWithTouch:(UITouch*)touch withEvent:(UIEvent*)event

May this will help you :)


Though trigonometry is one approach to the math, it's simpler and requires much less processor power to do this with vectors.

A picture for reference:

How can i make an image to rotate based on the direction of my finger swipe

The center of the dial you want to spin is point C.

From the user interface you must get a swipe start point A and "swipe vector" s that shows how the user's finger is moving. If the OS provides only a second point B some time after A, then compute s = B - A.

You want to compute the component of s that's tangent to the circle centered at C passing through A. This will allow the user to start his/her swipe anywhere and have it treated as a torque about point C. This ought to be intuitive.

This is not hard. The radius of the circle is shown as vector r = A - C. The perpendicular to this vector is called "r perp" shown with the "thumbtack" symbol in the picture. It is just the point (-y, x) where x and y are the components of r.

The signed length of the projection of p onto perp(r) is just a normalized dot product:

How can i make an image to rotate based on the direction of my finger swipe

This is a scalar that is positive if rotation is counter clockwise around C and negative if clockwise. So the sign tells you the direction of rotation. The absolute value tells you how much or how fast to rotate.

Suppose we already have swipe vector s stored as sx and sy and center C as cx and cy. Then the pseudo code is just:

r_perp_x = cy - ay; r_perp_y = ax - cx;
signed_length_p = (sx * r_perp_x + sy * r_perp_y) / sqrt(r_perp_x ^ 2 + r_perp_y ^ 2)

The desired number is signed_length_p.

The only caveat is to ignore touches A that are close to C. They can produce very large output values or division by zero. This is easy to fix. Just check the length of r and quit if it's less than some reasonable value.


If your current solution is "almost fine" for you - simplest thing to do would be ...just fixing it with two more areas:

How can i make an image to rotate based on the direction of my finger swipe

Now you spin your image clockwise whenever user swiped
- right or up (started in area A)
- right or down (started in area B)
- left or down (started in area D)
- left or up (started in area C)

....else - spin it anticlockwise.


I have done something similar with Xamarin.iOS but I doubt you want to see C# code so maybe this GitHub project will give you the necessary info:

https://github.com/hollance/MHRotaryKnob

0

精彩评论

暂无评论...
验证码 换一张
取 消