如何根据手指滑动的方向使图像旋转

时间:2010-09-21 07:15:40

标签: iphone-sdk-3.0

我正在尝试根据用户滑动来旋转圆形图像。现在我已经考虑过两个部分了。一个是左侧,另一个是右侧。 如果用户从右半部分向下滑动则意味着它顺时针旋转并且向上滑动意味着反时钟。在左侧,我做了反过来。所以现在我的图像只有当我触摸左半边和右半边时才会旋转...触摸顶部和底部..它的表现不同。 我甚至试过计算弧度......它也没用 任何人都可以建议我以更好的方式识别顺时针或逆时针......

谢谢你, 拉克希米琼斯

5 个答案:

答案 0 :(得分:5)

你应该用trignometry来解决这个问题。假设你知道滑动的起点(a1,b1)和滑动的终点(a2,b2) 圆心位于(x,y)

enter image description here

如果我们知道由线(x,y) - >(a1,b1)和(x,y) - >(a2,b2)产生的角度差异,我们将知道是顺时针还是逆时针旋转关于上述角度是正面还是负面。

由线条产生的角度计算如下。 让红色角度为红色

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
  }
}

请参阅here以了解如何计算tan-inverse。

同样计算角度绿色的值。在这样做之后,只需比较绿色和红色的值就会让你知道该怎么做。

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

通过使用滑动的加速度/速度数据,您可以使用相同的加速度/速度旋转圆圈。

答案 1 :(得分:1)

你有没有尝试过this教程来解决你的问题。这将对您有所帮助。

用于计算滑动的.h文件

#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;

.m文件是

#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

可帮助您跟踪滑动的主要方法是

- (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

这可以帮助你:)

答案 2 :(得分:0)

虽然三角法是数学的一种方法,但它更简单,并且需要更少的处理器能力来完成向量。

参考图片:

enter image description here

要旋转的表盘中心指向 C

在用户界面中,您必须获得滑动起点 A 和&#34;滑动矢量&#34; s ,显示用户手指的移动方式。如果操作系统在 A 之后的某个时间仅提供 B 的第二个点,则计算 s = B - A 即可。

您想要计算 s 切线的分量到以 C 为中心的圆圈,通过 A 即可。这将允许用户在任何地方开始他/她的滑动并将其视为关于点 C 的扭矩。这应该是直观的。

这并不难。圆的半径显示为向量 r = A - C 。与该向量垂直的称为&#34; r perp&#34;与&#34;图钉&#34;一起显示图中的符号。它只是点(-y,x),其中x和y是 r 的组成部分。

p 投射到perp( r )的签名长度只是一个标准化的点积:

enter image description here

如果旋转在 C 附近逆时针旋转,则为正标量,如果顺时针旋转则为负。所以标志告诉你旋转的方向。绝对值告诉您旋转的速度或速度。

假设我们已将滑动矢量 s 存储为sxsy并将 C 中心存储为cx和{{1 }}。那么伪代码只是:

cy

所需的数字为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)

唯一需要注意的是忽略接近 C 的触摸 A 。它们可以产生非常大的输出值或除以零。这很容易解决。只需检查 r 的长度,如果它小于某个合理的值,则退出。

答案 3 :(得分:0)

如果您当前的解决方案对您来说“几乎没问题” - 最简单的事情就是......只需要修复两个区域: starting swipe areas

现在,只要用户轻扫,您就可以顺时针旋转图像 - 向右或向上(在A区开始)
- 向右或向下(从区域B开始)
- 左或下(从区域D开始)
- 左或上(在C区开始)

....其他 - 逆时针旋转它。

答案 4 :(得分:0)

我和Xamarin.iOS做过类似的事情,但我怀疑你是否想看C#代码所以也许这个GitHub项目会给你必要的信息:

https://github.com/hollance/MHRotaryKnob