iOS:一用就上癮的刮刮樂視圖

彩票刮刮樂.png

Github倉庫地址

倉庫地址,喜歡就star一下❤️

前言

這是一個簡單卻功能強大的刮刮樂視圖,幾行代碼就可以實現刮刮樂效果,而且性能良好。下面有美女福利喲,相信我,你會喜歡的😍😍

相信大家都買過彩票刮刮樂,總是會抱着中大獎的情況去刮,希望自己是最幸運的那一個,刮中五百萬,抱得美人歸,從此走上人生巔峯。但現實往往是你口袋裏面的幾十塊零錢,幾分鐘就被消費殆盡了😂
許多APP也集成了這一功能,比如用支付寶線下支付後就有刮刮樂。雖然刮中的都是些沒多大用的優惠券,但總是會吸引人去刮一刮,萬一中了大獎呢😎

實現效果

多說無益,先來看看實現的效果吧

彩票刮刮樂

彩票刮刮樂.gif

美女刮刮樂

美女刮刮樂.gif

參照了一個叫做“撕掉她的衣服”APP,效果非常sexy,有沒有一種心跳加快,血脈膨脹的感覺。(相信大家迫不及待想要體驗一下了,點擊https://fir.im/JXScratchView,通過safari打開該鏈接,安裝之後信任證書,就可以快速體驗了)相信我在空白處,雙擊一下,你會發現新大陸😍

調研

在網上搜索了一番,方案基本上就是這種:鏈接
核心代碼:

-(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, 20, 20);
    // 默認是去創建一個透明的視圖
    UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, NO, 0);
    // 獲取上下文(畫板)
    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圖層遮罩

原理

圖層解釋.png

如圖所示,只要用戶滑動的時候,更新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: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else {
            return
        }
        let point = touch.location(in: scratchContentView)
        maskPath.move(to: point)
    }

    open override func touchesMoved(_ touches: Set<UITouch>, with 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<UInt8>.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一下❤️

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章