![](/img/trans.png)
[英]UIImageView pixel-perfect `touches began` for non-transparent parts of UIImage
[英]Detect touches only on non-transparent pixels of UIImageView, efficiently
您如何有效地檢測僅在UIImageView
非透明像素上的觸摸?
考慮下面的圖像,與UIImageView
顯示。 目標是僅在觸摸發生在圖像的非透明(在這種情況下為黑色)區域時使手勢識別器響應。
hitTest:withEvent:
或pointInside:withEvent:
,盡管這種方法可能非常低效,因為這些方法在觸摸事件期間被多次調用。 這是我的快速實現:(基於檢索UIImage的像素alpha值 )
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
//Using code from https://stackoverflow.com/questions/1042830/retrieving-a-pixel-alpha-value-for-a-uiimage
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel,
1, 1, 8, 1, NULL,
kCGImageAlphaOnly);
UIGraphicsPushContext(context);
[image drawAtPoint:CGPointMake(-point.x, -point.y)];
UIGraphicsPopContext();
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0f;
BOOL transparent = alpha < 0.01f;
return !transparent;
}
這假定圖像與point
在同一坐標空間中。 如果繼續縮放,則可能必須在檢查像素數據之前轉換該point
。
看起來很快對我工作。 我估計約。 此方法調用0.1-0.4 ms。 它沒有內部空間,可能不是最佳的。
在github上,您可以找到Ole Begemann的一個項目,該項目擴展了UIButton
,使其僅檢測按鈕圖像不透明的觸摸。
由於UIButton
是UIView
的子類,因此將其調整為UIImageView
應該很簡單。
希望這可以幫助。
好吧,如果你需要真的很快,你需要預先計算面具。
以下是如何提取它:
UIImage *image = [UIImage imageNamed:@"some_image.png"];
NSData *data = (NSData *) CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
unsigned char *pixels = (unsigned char *)[data bytes];
BOOL *mask = (BOOL *)malloc(data.length);
for (int i = 0; i < data.length; i += 4) {
mask[i >> 2] = pixels[i + 3] == 0xFF; // alpha, I hope
}
// TODO: save mask somewhere
或者您可以使用1x1位圖上下文解決方案來預先計算掩碼。 擁有掩碼意味着您可以使用一個索引內存訪問的成本來檢查任何點。
至於檢查比一個像素更大的區域 - 我會檢查一個圓上的像素,其中心位於觸摸點。 圓圈上大約16個點就足夠了。
同時檢測內部像素:另一個預先計算步驟 - 您需要找到蒙版的凸包。 您可以使用“Graham掃描”算法http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm執行此操作。然后填充蒙版中的該區域,或者保存多邊形並使用多邊形點測試。
最后,如果圖像有變換,則需要將點坐標從屏幕空間轉換為圖像空間,然后您可以檢查預先計算的蒙版。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.