Как я могу сделать изображение для поворота в зависимости от направления движения пальца - PullRequest
5 голосов
/ 21 сентября 2010

Я пытаюсь закрутить круговое изображение, основанное на ударе пользователя. Теперь я рассмотрел две части. одна левая сторона, а другая правая. Если пользователь проведет пальцем вниз от правой половины, это означает, что он вращается по часовой стрелке, а движение вверх означает против часовой стрелки. В левой части я сделал наоборот. Так что теперь мое изображение будет нормально вращаться только тогда, когда я коснусь левой и правой половины ... при касании сверху и снизу ... оно ведет себя по-разному. Я даже пытался вычислить радианы .. его тоже не работает Может ли кто-нибудь посоветовать мне лучше идентифицировать по часовой стрелке или против часовой стрелки ...

Спасибо, Лакшми Джонс

Ответы [ 5 ]

5 голосов
/ 03 января 2014

Вы должны подойти к этой проблеме с помощью тригнометрии.Предполагая, что вы знаете начальную точку прокрутки (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
  }
}

См. здесь , чтобы узнать, как рассчитать значение обратного загара.

Аналогичным образом рассчитайте значение угла зеленого цвета.После этого, просто сравнив значения зеленого и красного, вы узнаете, что делать.

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

Используя данные ускорения / скорости, вы можете вращать круг с тем же ускорением / скоростью.

1 голос
/ 28 декабря 2013

Вы когда-нибудь пробовали этот учебник для вашей проблемы.Это вам наверняка поможет.

.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

Может это вам поможет:)

0 голосов
/ 04 января 2014

Я сделал нечто подобное с Xamarin.iOS, но я сомневаюсь, что вы хотите увидеть код C #, поэтому, возможно, этот проект GitHub предоставит вам необходимую информацию:

https://github.com/hollance/MHRotaryKnob

0 голосов
/ 04 января 2014

Если ваше текущее решение «почти подходит» для вас - проще всего было бы ... просто исправить его еще двумя областями: starting swipe areas

Теперь вы поворачиваете изображение по часовой стрелке всякий раз, когда пользователь проводил пальцем
- вправо или вверх (начало в области A)
- вправо или вниз (начало в области B)
- влево или вниз (начало в области D)
- влево или вверх (начало в областиC)

.... иначе - поверните его против часовой стрелки.

0 голосов
/ 03 января 2014

Хотя тригонометрия является одним из подходов к математике, она проще и требует гораздо меньше ресурсов процессора, чтобы сделать это с векторами.

Изображение для справки:

enter image description here

Центром циферблата, который вы хотите вращать, является точка C .

Из пользовательского интерфейса вы должны получить начальную точку прокрутки A и «вектор прокрутки» s , который показывает, как движется палец пользователя. Если ОС предоставляет только вторую точку B через некоторое время после A , то вычисляется s = B - A .

Вы хотите вычислить компонент s , который является касательной к окружности с центром в C , проходящей через A . Это позволит пользователю начать свое движение в любом месте и рассматривать его как крутящий момент около точки C . Это должно быть интуитивно понятно.

Это не сложно. Радиус круга отображается в виде вектора r = A - C . Перпендикуляр к этому вектору называется «r perp», обозначенный на рисунке символом «чертёжная кнопка». Это просто точка (-y, x), где x и y являются компонентами r .

Длина проекции со знаком p на perp ( r ) со знаком является просто нормализованным точечным произведением:

enter image description here

Это скаляр, который положителен, если вращение против часовой стрелки вокруг C , и отрицателен, если по часовой стрелке. Так что знак говорит вам направление вращения. Абсолютное значение говорит вам, сколько или как быстро вращаться.

Предположим, у нас уже есть вектор смахивания s , сохраненный как sx и sy и центр C как cx и 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)

Желаемое число signed_length_p.

Единственное предостережение - игнорировать прикосновения A , близкие к C . Они могут давать очень большие выходные значения или деление на ноль. Это легко исправить. Просто проверьте длину r и выйдите, если она меньше некоторого разумного значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...