美文网首页
iOS 简易转盘+互动按钮

iOS 简易转盘+互动按钮

作者: Yimmm | 来源:发表于2022-02-22 23:17 被阅读0次

需求:一个简单的圆形转盘菜单,其中按钮平分为5个扇形区域。
解决方案:让UI把按钮图片切成5个独立的图片,其中除去扇形互动区域外为透明,利用UIImage的rgb色值判断alpha,若alpha值 >= 0.1才进行按钮交互动作。

1. 新建一个UIImage的分类(GetPixelRGBA):

//
//  UIImage+GetPixelRGBA.h
//  
//
//  Created by mac on 2022/1/19.
//  Copyright © 2021 Yim. All rights reserved.
//


#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIImage (GetPixelRGBA)

/// 获取图片点击位置的UIColor对象
-(UIColor *)colorAtPoint:(CGPoint)point WithImageSize:(CGSize)size;

@end

NS_ASSUME_NONNULL_END

//  
//
//  Created by mac on 2022/1/19.
//  Copyright © 2021 Yim. All rights reserved.
//

#import "UIImage+GetPixelRGBA.h"


@implementation UIImage (GetPixelRGBA)

// 取得 point pixel color
-(UIColor*)colorAtPoint:(CGPoint)point WithImageSize:(CGSize)size{
    UIImage *resizeimage = [self reSizeImage:self toSize:size];
    
    CGRect rect = CGRectMake(0.0f, 0.0f, resizeimage.size.width, resizeimage.size.height);
    if (CGRectContainsPoint(rect, point) == NO)  {return nil;}
    
    CGImageRef image = resizeimage.CGImage;
    size_t width = CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);
    int bytesPerPixel = 4;
    int bytesPerRow = (bytesPerPixel*1);
    unsigned char pixelData[4] = {0, 0, 0, 0};
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    
    if (context == NULL)  {
        NSLog(@"[colorAtPixel] Unable to create context!");
        return nil;
    }
    
    CGContextSetBlendMode(context, kCGBlendModeCopy);
    CGFloat pointX = point.x;
    CGFloat pointY = height-point.y;
    CGContextTranslateCTM(context, -pointX, -pointY);
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), image);
    CGContextRelease(context);
    
    //Convert color values [0..255] to floats [0.0..1.0]
    CGFloat red = (CGFloat)pixelData[0]/255.0f;
    CGFloat green = (CGFloat)pixelData[1]/255.0f;
    CGFloat blue = (CGFloat)pixelData[2]/255.0f;
    CGFloat alpha = (CGFloat)pixelData[3]/255.0f;
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}

// 更改 UIImage 大小
-(UIImage *)reSizeImage:(UIImage *)image toSize:(CGSize)reSize
{
    UIGraphicsBeginImageContext(CGSizeMake(reSize.width, reSize.height));
    [image drawInRect:CGRectMake(0, 0, reSize.width, reSize.height)];
    UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return reSizeImage;
}


@end

CGBitmapContextCreate();
通过颜色空间模式创建位图上下文,得到所需的 rgb色值 和 alpha 的数据pixelData[4]

CGContextSetBlendMode(context, kCGBlendModeCopy)
其中kCGBlendModeCopy: R = S,S: Source, 表示包含alpha的原色(Sa对应透明度值: 0.0-1.0)

2. 新建一个baseButton类,导入"UIImage+GetPixelRGBA.h"分类

//
//  NonRectButton.h
//  
//
//  Created by mac on 2022/1/19.
//  Copyright © 2021 Yim. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface NonRectButton : UIButton

@end

NS_ASSUME_NONNULL_END

//
//  NonRectButton.m
//  
//
//  Created by mac on 2022/1/19.
//  Copyright © 2021 Yim. All rights reserved.
//

#import "NonRectButton.h"
#import "UIImage+GetPixelRGBA.h"

@implementation NonRectButton


-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event  {
    
    UIImage *image = [self backgroundImageForState:UIControlStateNormal];
    if (image == nil)  
    {
        return YES;
    }
  
    CGColorRef color = [[image colorAtPoint:point WithImageSize:self.frame.size] CGColor];
    CGFloat alphaValue = CGColorGetAlpha(color);
    return (alphaValue >= 0.1f);
}
 

@end

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

是UIView提供的触摸事件处理方法。

触摸UIView时事件处理流程:

(1)当用户点击屏幕时,会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中

(2)UIApplication会从事件队列中取出最前面的事件进行分发以便处理,通常,先发送事件给应用程序的主窗口(UIWindow)

(3)主窗口会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到一个最合适的UIView来处理触摸事件

其中,先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:

  • 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil。
  • 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕:

重写pointInside方法,遍历当前触摸点内所有视图,就可以运用事先写好的colorAtPoint:(CGPoint)point WithImageSize:(CGSize)size方法,来获取透明值alphaValue ,通过判断alphaValue 是否存在来判定应该响应的按钮,从而达到正确的触发不规则按钮的图片相互重叠时的响应事件。

相关文章

网友评论

      本文标题:iOS 简易转盘+互动按钮

      本文链接:https://www.haomeiwen.com/subject/dvvscltx.html