iOS 简易转盘+互动按钮

2022-02-22  本文已影响0人  Yimmm

需求:一个简单的圆形转盘菜单,其中按钮平分为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方法,遍历当前触摸点内所有视图,就可以运用事先写好的colorAtPoint:(CGPoint)point WithImageSize:(CGSize)size方法,来获取透明值alphaValue ,通过判断alphaValue 是否存在来判定应该响应的按钮,从而达到正确的触发不规则按钮的图片相互重叠时的响应事件。

上一篇 下一篇

猜你喜欢

热点阅读