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

金字塔程式設計師發表於2018-06-25

彩票刮刮樂.png

Github倉庫地址

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

前言

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

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

實現效果

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

彩票刮刮樂

彩票刮刮樂.gif

美女刮刮樂

美女刮刮樂.gif

參照了一個叫做“撕掉她的衣服”APP,效果非常sexy,有沒有一種心跳加快,血脈膨脹的感覺。(相信大家迫不及待想要體驗一下了,點選fir.im/JXScratchVi…,通過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一下❤️

相關文章