源码

iOS:一用就上瘾的刮刮乐视图

Github仓库地址

仓库地址,喜欢就star一下

前言

这是一个简单却功能强大的刮刮乐视图,几行代码就可以实现刮刮乐效果,而且性能良好。下面有美女福利哟,相信我,你会喜欢的

相信大家都买过彩票刮刮乐,总是会抱着中大奖的情况去刮,希望自己是最幸运的那一个,刮中五百万,抱得美人归,从此走上人生巅峰。但现实往往是你口袋里面的几十块零钱,几分钟就被消费殆尽了

许多APP也集成了这一功能,比如用支付宝线下支付后就有刮刮乐。虽然刮中的都是些没多大用的优惠券,但总是会吸引人去刮一刮,万一中了大奖呢

实现效果

多说无益,先来看看实现的效果吧

彩票刮刮乐

调研

在网上搜索了一番,方案基本上就是这种:链接

核心代码:

-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    // 触摸任意位置
    UITouch *touch = touches.anyObject;
    // 触摸位置在图片上的坐标
    CGPoint cententPoint = [touch locationInView:self.imageView];
    // 设置清除点的大小
    CGRect  rect = CGRectMake(cententPoint.x, cententPoint.y, 2020);
    // 默认是去创建一个透明的视图
    UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, NO0);
    // 获取上下文(画板)
    CGContextRef ref = UIGraphicsGetCurrentContext();
    // 把imageView的layer映射到上下文中
    [self.imageView.layer renderInContext:ref];
    // 清除划过的区域
    CGContextClearRect(ref, rect);
    // 获取图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    // 结束图片的画板, (意味着图片在上下文中消失)
    UIGraphicsEndImageContext();

    self.imageView.image = image;

}

缺点很明显:

1、画笔是矩形的,看着很难受;

2、绘画的核心代码用了CoreGraphics,每次移动都要重新开启一个context上下文,绘制image,对CPU的性能有很大的消耗。点击该链接,详细了解CAShapeLayer比CG的优势

所以,我想了一个骚技巧,用CAShapeLayer作为mask来实现该效果。点击该链接,了解mask图层遮罩

原理

如图所示,只要用户滑动的时候,更新contentView的maskLayer的path,就可以实现刮刮乐的效果了。代码如下:

  • 初始化

/// 指定初始化器
    ///
    /// - Parameters:
    ///   - contentView: 内容视图,比如彩票的奖品详情内容。(需要隐藏起来的内容)
    ///   - maskView: 遮罩视图
    public init(contentView: UIView, maskView: UIView) {
        super.init(frame: CGRect.zero)

        scratchMaskView = maskView
        self.addSubview(scratchMaskView)

        scratchContentView = contentView
        self.addSubview(scratchContentView)

        maskLayer = CAShapeLayer()
        maskLayer.strokeColor = UIColor.red.cgColor
        maskLayer.lineWidth = strokeLineWidth
        maskLayer.lineCap = strokeLineCap
        scratchContentView?.layer.mask = maskLayer

        maskPath = UIBezierPath()
    }
  • 绘画核心代码

open override func touchesBegan(_ touches: Setwith event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }
        let point = touch.location(in: scratchContentView)
        maskPath.move(to: point)
    }

    open override func touchesMoved(_ touches: Setwith event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }
        let point = touch.location(in: scratchContentView)
        maskPath.addLine(to: point)
        maskPath.move(to: point)
        maskLayer.path = maskPath.cgPath
    }
  • 获取已经刮了多少百分比,比如用户刮了70%的时候,就显示全部。

//获取透明像素占总像素的百分比
    private func getAlphaPixelPercent(img: UIImage) -> Float {
        //计算像素总个数
        let width = Int(img.size.width)
        let height = Int(img.size.height)
        let bitmapByteCount = width * height

        //得到所有像素数据
        let pixelData = UnsafeMutablePointer.allocate(capacity: bitmapByteCount)
        let colorSpace = CGColorSpaceCreateDeviceGray()
        let context = CGContext(data: pixelData,
                                width: width,
                                height: height,
                                bitsPerComponent: 8,
                                bytesPerRow: width,
                                space: colorSpace,
                                bitmapInfo: CGBitmapInfo(rawValue:
                                    CGImageAlphaInfo.alphaOnly.rawValue).rawValue)!
        let rect = CGRect(x: 0, y: 0, width: width, height: height)
        context.clear(rect)
        context.draw(img.cgImage!, in: rect)


        //计算透明像素个数
        var alphaPixelCount = 0
        for x in 0...Int(width) {
            for y in 0...Int(height) {
                if pixelData[y * width + x] == 0 {
                    alphaPixelCount += 1
                }
            }
        }

        free(pixelData)

        return Float(alphaPixelCount) / Float(bitmapByteCount)
    }
    //展示全部
    open func showContentView() {
        self.scratchContentView.layer.mask = nil
    }

使用

彩票刮刮乐示例代码

        let contentView = UILabel()
        contentView.backgroundColor = UIColor.white
        contentView.textAlignment = .center
        contentView.font = UIFont.systemFont(ofSize: 25)
        contentView.text = "恭喜你刮中500万"
        contentView.numberOfLines = 0

        let maskView = UIView()
        maskView.backgroundColor = UIColor.lightGray

        let ratio = self.bounds.size.width/400
        scratchView = JXScratchView(contentView: contentView, maskView: maskView)
        scratchView.delegate = self
        scratchView.strokeLineWidth = 25
        scratchView.strokeLineCap = kCALineCapRound
        scratchView.frame = CGRect(x: 33*ratio, y: 140*ratio, width: 337*ratio, height: 154*ratio)
        addSubview(scratchView)
  • 指定使用JXScratchView的public init(contentView: UIView, maskView: UIView)初始化器,只需要传入UIView及其子类就可以了。

  • strokeLineCap属性设置stroke形状,默认kCALineCapRound

  • strokeLineWidth属性设置stroke线宽,默认20

  • 遵从JXScratchViewDelegate,实现func scratchView(scratchView: JXScratchView, didScratched percent: Float)代理方法,就可以实时获取刮刮乐的百分比。

  • 建议新建一个UIView,把JXScratchView封装进去,可以参考JXScratchTicketView

Github仓库地址

仓库地址,喜欢就star一下

作者:暴走的鑫鑫

链接:https://www.jianshu.com/p/0139a2a22857

(0)

本文由 投稿者 创作,文章地址:https://blog.isoyu.com/archives/iosyiyongjiushangyindeguagualeshitu.html
采用知识共享署名4.0 国际许可协议进行许可。除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为:9 月 12, 2018 at 10:48 下午

热评文章

发表回复

[必填]

我是人?

提交后请等待三秒以免造成未提交成功和重复