【问题标题】:How to detect area while tapping inside circle in ios如何在ios中点击内圈时检测区域
【发布时间】:2014-06-23 22:43:08
【问题描述】:

我想在圆圈内点击时找到该区域。其实我也做过一次计算,但不准确。

检查我编写的代码 sn-p,以便在我的循环视图中找到选项卡的位置。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event" this method

     float  dx = touchLocation.x -160;
     float  dy = touchLocation.y - 240;
     double angle = atan2(touchLocation.x,touchLocation.y);
 /* Device is iPad */
            if (count==4) {


                if(angle>-1.639&&angle<=0.775)
                {
                    area=1;
                    NSLog(@"touched here  1 ********************************** ");
                }
                else if(angle>0.775&&angle<=1.579)
                {
                    area=2;
                    NSLog(@"touched here   2********************************** ");
                }
                else if(angle>1.579&&angle<=2.466)
                {
                    area=3;NSLog(@"touched here   3********************************** ");
                }
                else
                {
                    area=4;NSLog(@"touched here  4 ********************************** ");
                }


            }
            else  if (count==5) {


                if(angle>-1.520&&angle<=0.553)
                {
                    area=1;
                    NSLog(@"touched here  1 ********************************** ");
                }
                else if(angle>0.553&&angle<=1.262)
                {
                    area=2;
                    NSLog(@"touched here   2********************************** ");
                }
                else if(angle>1.262&&angle<=1.884)
                {
                    area=3;NSLog(@"touched here   3********************************** ");
                }
                else if(angle>1.884&&angle<=2.644)
                {
                    area=4;NSLog(@"touched here  4 ********************************** ");
                }

                else
                {
                    area=5;NSLog(@"touched here  5 ********************************** ");
                }


            }
            else  if (count==6) {


                if(angle>-1.5707&&angle<=0.4692)
                {
                    area=1;
                    NSLog(@"touched here  1 ********************************** ");
                }
                else if(angle>0.4692&&angle<=1.0219)
                {
                    area=2;
                    NSLog(@"touched here   2********************************** ");
                }
                else if(angle>1.0219&&angle<=1.5707)
                {
                    area=3;NSLog(@"touched here   3********************************** ");
                }
                else if(angle>1.5707&&angle<=2.1147)
                {
                    area=4;NSLog(@"touched here  4 ********************************** ");
                }
                else if(angle>2.1147&&angle<=2.7245)
                {
                    area=5;NSLog(@"touched here  5 ********************************** ");
                }
                else
                {
                    area=6;NSLog(@"touched here  6 ********************************** ");
                }


            }
            else  if (count==7) {


                if(angle>-1.5707&&angle<=0.3992)
                {
                    area=1;
                    NSLog(@"touched here  1 ********************************** ");
                }
                else if(angle>0.3992&&angle<=0.8602)
                {
                    area=2;
                    NSLog(@"touched here   2********************************** ");
                }
                else if(angle>0.8602&&angle<=1.346)
                {
                    area=3;NSLog(@"touched here   3********************************** ");
                }
                else if(angle>1.346&&angle<=1.812)
                {
                    area=4;NSLog(@"touched here  4 ********************************** ");
                }
                else if(angle>1.812&&angle<=2.304)
                {
                    area=5;NSLog(@"touched here  5 ********************************** ");
                }
                else if(angle>2.304&&angle<=2.828)
                {
                    area=6;NSLog(@"touched here  6 ********************************** ");
                }

                else
                {
                    area=7;NSLog(@"touched here  7 ********************************** ");
                }


            }
            else if (count==8){

                if(angle>-1.40&&angle<=0.45)
                {
                    area=1;
                    NSLog(@"touched here  1 ********************************** ");
                }
                else if(angle>.45&&angle<=.73)
                {
                    area=2;
                    NSLog(@"touched here   2********************************** ");
                }
                else if(angle>.73&&angle<=1.15)
                {
                    area=3;NSLog(@"touched here   3********************************** ");
                }
                else if(angle>1.15&&angle<=1.55){
                    area=4;NSLog(@"touched here  4 ********************************** ");
                }
                else if(angle>-1.55&&angle<=1.95){
                    area=5;NSLog(@"touched here  5 ********************************** ");
                }
                else if(angle>-1.95&&angle<=2.43){
                    area=6;NSLog(@"touched here  6 ********************************** ");
                }
                else if(angle>2.43&&angle<=2.98){
                    area=7;NSLog(@"touched here   7********************************** ");
                }

                //     else if(angle>2.98&&angle<=-1.40){
                else
                {
                    area=8;NSLog(@"touched here  8 ********************************** ");
                }

            } 

【问题讨论】:

  • 小伙伴问题不清楚请详细说明...
  • 正如 amar 指出的 - 我们根本不知道您的目标是什么。能给我们更详细的解释吗?
  • @Tander,我想找到角度部分之间的部分。请查看我的代码 sn-p

标签: ios atan2


【解决方案1】:

假设您的周期UIView 是cycleView。那么这可能是您的解决方案:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    UITouch *touch = [[event allTouches] anyObject];
    CGPoint touchLocation = [touch locationInView:cycleView];

    if(touchLocation.y < cycleView.frame.size.height/2 && touchLocation.x < cycleView.frame.size.width/2){
        //touch is in upper left corner
    } else if(touchLocation.y < cycleView.frame.size.height/2 && touchLocation.x >= cycleView.frame.size.width/2){
        //touch is in upper right corner
    } else if(touchLocation.y >= cycleView.frame.size.height/2 && touchLocation.x < cycleView.frame.size.width/2){
        //touch is in lower left corner
    } else if(touchLocation.y >= cycleView.frame.size.height/2 && touchLocation.x >= cycleView.frame.size.width/2){
        //touch is in upper left corner
    }
}

如果每个饼图都是一个 UIView 会更容易,像这样您可以单独调用每个饼图。

【讨论】:

  • Kevin Chromik,我想检测圆形区域内的触摸。
  • @Mannnu,你是说内循环吗?因此,您可能可以使用循环 UIView 和另一个较小的循环 UIView 作为子视图。
  • 我的饼图会变化 4 到 8 部分我该如何检测每个部分
  • ,请查看新图片
  • @Mannnu 我认为这更容易,如果您为每件作品使用单独的UIViews。您将更加灵活地添加更多片段或更改它们的大小。然后,要检测其中一个上的触摸,您只需要为特定的新块添加触摸检测。
【解决方案2】:

这里有一些想法,Kevin 的回答很好,但不能概括为更多切片。

假设你在一个圆上有 n 个相等的切片。每个切片 2*PI/n 度。要找到对应的切片,您必须从三角学中获得一些帮助,特别是我们将使用反正切。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:cycleView];

double radius = self.bounds.size.width;
double sliceAngle = M_PI*2 / n;

double deltaAngle = atan2(radius - touchLocation.y,touchLocation.x - radius);
//Here you might get a negative value for delta angle, 
//just keep adding 2*M_PI to the result until you get a deltaAngle between 0 and 2*M_PI
//also notice that we are normalizing the aran values for the center of our frame, which is
//the origin of the circle (keep in mind that origin is the upper left corner in UIKit)

NSInteger sliceNumber = ((NSInteger)floor(deltaAngle/sliceAngle)) 
}

您还可以做一件事,因为您有一个圆圈,但 UIView 应该有矩形形状,您可以重写 pointInside 方法以仅捕获圆圈内的触摸。它看起来像这样:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
//Assuming you have a circle, not an ellipse. And also that your frame is a square.

//Get the length of the touch point from the origin and make sure it's smaller than
//your circles radius

CGFloat length = sqrtf(point.x * point.x + point.y * point.y);
return (length < self.bounds.size.width); 
//could have used height as well since you have a square
}

这些 sn-ps 未经测试,如果它们不能按预期工作,请告诉我。

【讨论】:

  • +1 from me.. 但在您的 atan2 计算中,您需要考虑到视图的 (0, 0) 实际上是左上角。
  • @Kaan Dedeoglu。实际上,这行代码 self.bounds.size.width 的意思是我在输入上述行时出错。
  • @Aky你说的很对,谢谢指正,我加了点变换和合适的cmets,你要看看就看看。
【解决方案3】:

更新:添加了完整的工作代码

这里有一些伪代码可以帮助您找出您点击的位置。这是参考最上面的图。 (我假设你的圆心与视图的中心重合):

(1)求圆心到接触点的线段方向:

dx = touchPoint.x - circleCenter.x;
dy = touchPoint.y - circleCenter.y;
t = atan2(dy, dx); // some offsetting/direction adjustment might be required

(2) 找出触摸点位于哪个八分圆中。

octant = floor(4 * t/M_PI); // will return a number between 0 and 7.

如果您的扇区大小不均匀(但您知道每个扇区的角度大小),您可以使用 if-else 序列。

(3) 右侧的八分圆各有一个“内扇形”和一个环形。如果要测试触摸发生在哪两个部分,可以先计算触摸点到圆心的距离:

dist = sqrtf(dx * dx + dy * dy);

显然你需要知道每个八分圆的内半径,然后进行测试

if ( dist < innerRadius[i]) ... // again, you might need to adjust the angle calculations to ensure that the right indices correspond to the right sector. See (working) code below...

innerRadius[8] 是一个包含每个八分圆内半径的数组。

以下是一些实际工作代码,它们以编程方式生成饼图并正确检测点击位置。只需将“单一视图应用程序”模板中ViewController.m 的内容替换为:

#import "ViewController.h"

static float innerRadii[] = {50, 75, 100, 125, 150, 175, 200, 225};
@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    float side = 600; // square view
    CGPoint center = CGPointMake(side/2, side/2);
    CGFloat radius = side/2 * 0.9;

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(side, side), YES, 0.0);
    UIBezierPath *bgPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, side, side)];
    [[UIColor lightGrayColor] setFill];
    [bgPath fill];
    for (int i = 0; i < 8; i++)
    {
        UIBezierPath *sector = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:M_PI/4 * i endAngle:M_PI/4 * (i+1) clockwise:YES];
        [sector addLineToPoint:center];
        [sector closePath];
#define VAL(x) x/2 + 0.25

        [[UIColor colorWithRed:VAL((float)(i % 2)) green:VAL((float)((i >> 1) % 2)) blue:VAL((float)((i >> 2) % 2)) alpha:1.0] setFill];
        [sector fill];

        UIBezierPath *innerSector = [UIBezierPath bezierPathWithArcCenter:center radius:innerRadii[i] startAngle:M_PI/4 * i endAngle:M_PI/4 * (i+1) clockwise:YES];
        [innerSector addLineToPoint:center];
        [innerSector closePath];
#define VAL1(x) (1- x)/3 + 0.5

        [[UIColor colorWithRed:VAL1((float)(i  % 2)) green:VAL1((float)((i >> 1) % 2)) blue:VAL1((float)((i >> 2) % 2)) alpha:1.0] setFill];
        [innerSector fill];

    }
    UIImage *pieChartImg = UIGraphicsGetImageFromCurrentImageContext();
    UIImageView *pieChartView = [[UIImageView alloc] initWithImage:pieChartImg];
    pieChartView.center = self.view.center;
    [self.view addSubview:pieChartView];

    UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(identifyTappedSector:)];
    pieChartView.userInteractionEnabled = YES;
    [pieChartView addGestureRecognizer:gr];
}

- (void)identifyTappedSector:(UITapGestureRecognizer *)tgr
{
    CGPoint touchPoint = [tgr locationInView:tgr.view];
    CGPoint circleCenter = CGPointMake(tgr.view.bounds.size.width/2, tgr.view.bounds.size.height/2);
    float dx = circleCenter.x - touchPoint.x;
    float dy = circleCenter.y - touchPoint.y;
    float t = atan2f(dy, dx) + M_PI;
    NSLog(@"angle = %f", t * 180.0/M_PI);
    int octant = floorf(4 * t/M_PI);

    NSLog(@"You tapped octant number: %d!", octant);
    float dist = sqrtf(dx * dx + dy * dy);
    if (dist <= innerRadii[octant])
        NSLog(@"\tYou tapped the inner sector!");
    else
        NSLog(@"\tYou tapped the annulus!");
}


@end

【讨论】:

  • 八分圆始终只返回 0 和 1
  • @Mannnu 我更正了伪代码中atan2 表达式中的一个愚蠢错误,请确保您的代码正确。
  • 这里所有变量(octant 除外)都应该是double
  • @Aky.i 更正了您的代码,但我的值仍然相同
  • 请将您的代码发布到 pastebin.com 并将链接发布到 cmets 中
猜你喜欢
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-20
  • 2018-06-18
  • 2020-07-30
相关资源
最近更新 更多