【问题标题】:layer hit test only returning layer when bottom half of layer is touched图层命中测试仅在触摸图层的下半部分时返回图层
【发布时间】:2010-09-28 21:35:12
【问题描述】:

我在支持图层的视图上有一个子图层。子图层的内容设置为 Image Ref,并且是 25x25 矩形。
当调用 touchesBegan 和 touchesMoved 方法时,我在超级层上执行命中测试。事实上,hit 测试方法确实会在子图层被触摸时返回,但仅在图像的下半部分被触摸时才返回。如果触摸图像的上半部分,则返回超级图层。

我知道 iPhone 操作系统会补偿用户触摸低于预期的趋势。即使我将子图层调整为更大的尺寸(50x50),它也会表现出相同的行为。

有什么想法吗?

【问题讨论】:

    标签: iphone cocoa-touch core-animation


    【解决方案1】:

    /// 添加frame.origin.y

        public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            let convertPoint = CGPoint(x:point.x, y:(point.y + frame.origin.y))
            let superPiont = self.layer.convert(convertPoint, to:layer.superlayer)
            selectlayer = layer.superlayer?.hitTest(superPiont)
            }
    

    【讨论】:

      【解决方案2】:

      接受的答案不能解决问题,但 schwa 的答案可以。

      我有一个窗口、一个视图控制器和视图。视图接收触摸并在其层上调用hitTest:。我遇到了同样的问题,发现视图中的点是正确的,但是在hitTest:中,该点的y坐标偏离了20px,恰好是状态栏的高度。

      按照 schwa 的建议,通过将点映射到超层的坐标系,这个问题得到了解决。 “神秘”的超级层是超级视图的根层。在我的例子中,它是窗口层(frame (0, 0, 320, 480))。

      【讨论】:

        【解决方案3】:

        hitTest 的文档说:

        /* Returns the farthest descendant of the layer containing point 'p'.
         * Siblings are searched in top-to-bottom order. 'p' is in the
         * coordinate system of the receiver's superlayer. */
        

        所以你需要做(像这样):

        CGPoint thePoint = [touch locationInView:self];
        thePoint = [self.layer convertPoint:thePoint toLayer:self.layer.superlayer];
        CALayer *theLayer = [self.layer hitTest:thePoint];
        

        (为了完整起见,重复其他帖子的答案)

        【讨论】:

        • 谢谢!我有同样的问题,这让我发疯。我仍然有点困惑为什么它是必要的,但它似乎正在工作。
        • 我认为一个问题是CA视图坐标是从UIView坐标翻转过来的(左下角是原点)?但我很想听听能详细说明视图和层层次结构并真正解释其他情况的人。
        • 这个答案为我节省了很多时间和悲伤——谢谢!还有一点我不明白:如果self是接收到触摸的视图,那么self.layer是它对应的层——那么self.layer.superlayer是什么?
        【解决方案4】:

        谢谢凯文...

        我最终只是用 UIViews 重做我的代码。只是想弄清楚为什么 UIView 不知道被触摸的是什么层太麻烦了。这个想法背后的全部原因是我将一次在屏幕上显示 100 多个项目,并且认为在处理器上层会比 UIViews 更容易。我现在已经启动并运行了该应用程序,并且 100 次查看并没有给它带来任何问题。

        我对其他人的建议是尽可能坚持命中测试 UIViews,它使代码更简单

        【讨论】:

          【解决方案5】:

          当我尝试你的代码时,我得到了几乎正确的行为,除了在子层的边缘经常无法识别触摸。我对发生了什么感到有些困惑。你可能想尝试做一些事情,比如当你注册一个触摸时,在触摸发生的地方扔一个新的小层(比如某种颜色的 5x5 正方形),然后在 3 秒后再次将其移除。这样您就可以跟踪 CA 认为触摸发生的位置与您的光标实际位置。

          顺便说一句,您不需要为蓝色内容创建 CGImage,您只需将图层的 backgroundColor 设置为 [UIColor blueColor].CGColor

          【讨论】:

            【解决方案6】:

            我已简化代码以找出问题所在。我在屏幕上只有一个子图层,没有子视图。上面列出的代码是我在模拟器中运行的。由于屏幕上只有 2 层,即宿主视图的支持层和我添加的子层,因此不会影响命中测试。

            如果不清楚,当子层的顶部被触摸时,命中测试会返回支持层。此外,如果我在子层正下方的某个点触摸支撑层,则命中测试会返回子层。

            这很难解释,但如果你运行代码,它就会变得清晰。

            谢谢

            【讨论】:

              【解决方案7】:

              如果仅在下半部分识别触摸,则一种可能性是另一个子视图覆盖了该子视图的上半部分。你有多个子视图还是只有一个图像?如果您有多个子视图并且其中任何一个的背景颜色为 clearColor,请尝试为其提供纯色背景颜色以进行测试。这样您就可以知道您的子视图是否被另一个子视图覆盖。

              希望对您有所帮助。

              【讨论】:

                【解决方案8】:

                似乎该层不只是接收底部像素的触摸。相反,似乎屏幕上的“实际”层和层的内容是由不同的 CGRect 定义的。图像显示在预期的坐标处,而响应触摸的层在图像下方偏移。下面,我的意思是图像的原点在 (200, 200),响应触摸的图层的原点在 (200, 220)。

                下面我发布了一些我用来重现问题的测试代码。首先是我的视图子类,然后是我的视图控制器。非常感谢这个问题背后的任何推理。

                我的视图子类:

                #import "myView.h"
                #import <QuartzCore/QuartzCore.h>
                
                
                @implementation myView
                
                
                - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
                
                    CGPoint currentLocation = [[touches anyObject] locationInView:self];
                
                    CALayer *currentLayer = [self.layer hitTest:currentLocation];
                
                    CGPoint center = [currentLayer position];
                
                    NSLog([currentLayer valueForKey:@"isRootLayer"]);
                
                    if(![currentLayer valueForKey:@"isRootLayer"]) {
                
                        if (center.x != 200) {
                
                            [currentLayer setPosition:CGPointMake(200.0f, 200.0f)];     
                
                        } else {
                            [currentLayer setPosition:CGPointMake(100.0f, 100.0f)];     
                
                        }
                    }
                }
                
                
                - (id)initWithFrame:(CGRect)frame {
                    if (self = [super initWithFrame:frame]) {
                        // Initialization code
                    }
                    return self;
                }
                
                
                - (void)drawRect:(CGRect)rect {
                    // Drawing code
                }
                
                
                - (void)dealloc {
                    [super dealloc];
                }
                
                
                @end
                

                我的视图控制器:

                #import "layerTestViewController.h"
                #import <QuartzCore/QuartzCore.h>
                
                
                #define ELEMENT_PERIOD_SIZE 50
                #define ELEMENT_GROUP_SIZE 50
                
                @implementation layerTestViewController
                
                
                
                
                
                // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
                - (void)viewDidLoad {
                    [super viewDidLoad];
                
                    CALayer  *myLayer = [CALayer layer];
                    CGRect layerFrame =CGRectMake(0.0f, 0.0f, ELEMENT_GROUP_SIZE, ELEMENT_PERIOD_SIZE);
                    myLayer.frame = layerFrame; 
                
                    [myLayer setName:[NSString stringWithString:@"test"]];
                    [myLayer setValue:[NSString stringWithString:@"testkey"] forKey:@"key"];
                
                    UIGraphicsBeginImageContext(layerFrame.size);
                    [[UIColor blueColor] set];
                    UIRectFill(layerFrame);
                    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
                    UIGraphicsEndImageContext();
                
                    myLayer.contents = (id)[theImage CGImage];
                    myLayer.position = CGPointMake(100.0f, 100.0f);
                
                    [self.view.layer addSublayer:myLayer];   
                
                    [self.view.layer setValue:[NSString stringWithString:@"YES"] forKey:@"isRootLayer"];
                    NSLog([self.view.layer valueForKey:@"isRootLayer"]);
                
                }
                
                
                
                
                - (void)didReceiveMemoryWarning {
                    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
                    // Release anything that's not essential, such as cached data
                }
                
                
                - (void)dealloc {
                    [super dealloc];
                }
                
                @end
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2012-12-21
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-07-29
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多