jumppage功能

This commit is contained in:
ddisfriend
2025-04-10 10:04:06 +08:00
parent a497e9981e
commit 1b0676b1e6
72 changed files with 12370 additions and 8077 deletions

22
Pods/DynamicBlurView/LICENSE generated Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Kyohei Ito
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

162
Pods/DynamicBlurView/README.md generated Normal file
View File

@@ -0,0 +1,162 @@
# DynamicBlurView
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Version](https://img.shields.io/cocoapods/v/DynamicBlurView.svg?style=flat)](http://cocoadocs.org/docsets/DynamicBlurView)
[![License](https://img.shields.io/cocoapods/l/DynamicBlurView.svg?style=flat)](http://cocoadocs.org/docsets/DynamicBlurView)
[![Platform](https://img.shields.io/cocoapods/p/DynamicBlurView.svg?style=flat)](http://cocoadocs.org/docsets/DynamicBlurView)
DynamicBlurView is a dynamic and high performance UIView subclass for Blur.
#### [Appetize's Demo](https://appetize.io/app/9pvxr367tm0jj2bcy8zavxnqkg?device=iphone6&scale=75&orientation=portrait)
![home](https://user-images.githubusercontent.com/5707132/33749021-0342ea8c-dc0f-11e7-9260-af2d2e9c8d0c.gif)![home](https://user-images.githubusercontent.com/5707132/33749025-07595de0-dc0f-11e7-8814-fe757f437b69.png)
- Since using the CADisplayLink, it is a high performance.
- Can generate a plurality of BlurView.
## Requirements
- Swift 4.2
- iOS 8.0 or later
- tvOS 9.0 or later
## How to Install DynamicBlurView
#### CocoaPods
Add the following to your `Podfile`:
```Ruby
pod "DynamicBlurView"
```
#### Carthage
Add the following to your `Cartfile`:
```Ruby
github "KyoheiG3/DynamicBlurView"
```
## Usage
### Example
Blur the whole
```swift
let blurView = DynamicBlurView(frame: view.bounds)
blurView.blurRadius = 10
view.addSubview(blurView)
```
Animation
```swift
UIView.animateWithDuration(0.5) {
blurView.blurRadius = 30
}
```
Ratio
```swift
blurView.blurRatio = 0.5
```
### Variable
```swift
var drawsAsynchronously: Bool
```
- When true, it captures displays image and blur it asynchronously. Try to set true if needs more performance.
- Asynchronous drawing is possibly crash when needs to process on main thread that drawing with animation for example.
- Default is false.
```Swift
var blurRadius: CGFloat
```
- Strength of the blur.
```Swift
var trackingMode: TrackingMode
```
- Mode for update frequency.
- `Common` is constantly updated.
- `Tracking` is only during scrolling update.
- `None` is not update.
```swift
var blendColor: UIColor?
```
- Blend in the blurred image.
```swift
var iterations: Int
```
- Number of times for blur.
- Default is 3.
```swift
var isDeepRendering: Bool
```
- If the view want to render beyond the layer, should be true.
- Default is false.
```swift
var blurRatio: CGFloat
```
- When none of tracking mode, it can change the radius of blur with the ratio. Should set from 0 to 1.
- Default is 1.
```swift
var quality: CaptureQuality
```
- Quality of captured image.
- Default is medium.
### Function
```swift
func refresh()
```
- Remove cache of blur image then get it again.
```swift
func remove()
```
- Remove cache of blur image.
```swift
func animate()
```
- Should use when needs to change layout with animation when is set none of tracking mode.
## Acknowledgements
- Inspired by [FXBlurView](https://github.com/nicklockwood/FXBlurView) in [nicklockwood](https://github.com/nicklockwood).
## Author
#### Kyohei Ito
- [GitHub](https://github.com/kyoheig3)
- [Twitter](https://twitter.com/kyoheig3)
Follow me 🎉
## LICENSE
Under the MIT license. See LICENSE file for details.

View File

@@ -0,0 +1,131 @@
//
// BlurLayer.swift
// DynamicBlurView
//
// Created by Kyohei Ito on 2017/08/14.
// Copyright © 2017 kyohei_ito. All rights reserved.
//
import UIKit
private extension CGRect {
func rectangle(_ s: CGSize) -> CGRect {
let x = origin.x / s.width
let y = origin.y / s.height
let width = size.width / s.width
let height = size.height / s.height
return CGRect(x: x, y: y, width: width, height: height)
}
}
class BlurLayer: CALayer {
private static let blurRadiusKey = "blurRadius"
private static let blurLayoutKey = "blurLayout"
@NSManaged var blurRadius: CGFloat
@NSManaged private var blurLayout: CGFloat
private var fromBlurRadius: CGFloat?
var presentationRadius: CGFloat {
if let radius = fromBlurRadius {
if let layer = presentation() {
return layer.blurRadius
} else {
return radius
}
} else {
return blurRadius
}
}
override class func needsDisplay(forKey key: String) -> Bool {
if key == blurRadiusKey || key == blurLayoutKey {
return true
}
return super.needsDisplay(forKey: key)
}
open override func action(forKey event: String) -> CAAction? {
if event == BlurLayer.blurRadiusKey {
fromBlurRadius = nil
if let action = super.action(forKey: "opacity") as? CABasicAnimation {
fromBlurRadius = (presentation() ?? self).blurRadius
action.keyPath = event
action.fromValue = fromBlurRadius
return action
}
}
if event == BlurLayer.blurLayoutKey, let action = super.action(forKey: "opacity") as? CABasicAnimation {
action.keyPath = event
action.fromValue = 0
action.toValue = 1
return action
}
return super.action(forKey: event)
}
}
extension BlurLayer {
func draw(_ image: UIImage, fixes isFixes: Bool, baseLayer: CALayer?) {
contents = image.cgImage
contentsScale = image.scale
if isFixes, let blurLayer = presentation() {
contentsRect = blurLayer.convert(blurLayer.bounds, to: baseLayer).rectangle(image.size)
}
}
func refresh() {
fromBlurRadius = nil
}
func animate() {
UIView.performWithoutAnimation {
blurLayout = 0
}
blurLayout = 1
}
func render(in context: CGContext, for layer: CALayer) {
let layers = hideOverlappingLayers(layer.sublayers)
layer.render(in: context)
layers.forEach {
$0.isHidden = false
}
}
private func hideOverlappingLayers(_ layers: [CALayer]?) -> [CALayer] {
var hiddenLayers: [CALayer] = []
guard let layers = layers else {
return hiddenLayers
}
for layer in layers.reversed() {
if isHang(to: layer) {
return hiddenLayers + hideOverlappingLayers(layer.sublayers)
}
if layer.isHidden == false {
layer.isHidden = true
hiddenLayers.append(layer)
}
if layer == self {
return hiddenLayers
}
}
return hiddenLayers
}
private func isHang(to target: CALayer) -> Bool {
var layer = superlayer
while layer != nil {
if layer == target {
return true
}
layer = layer?.superlayer
}
return false
}
}

View File

@@ -0,0 +1,33 @@
//
// CGContext+CGImage.swift
// DynamicBlurView
//
// Created by Kyohei Ito on 2017/08/17.
// Copyright © 2017 kyohei_ito. All rights reserved.
//
import UIKit
extension CGContext {
static func imageContext(with quality: CaptureQuality, rect: CGRect, opaque: Bool) -> CGContext? {
UIGraphicsBeginImageContextWithOptions(rect.size, opaque, quality.imageScale)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
context.translateBy(x: -rect.origin.x, y: -rect.origin.y)
context.interpolationQuality = quality.interpolationQuality
return context
}
func makeImage(with blendColor: UIColor?, blendMode: CGBlendMode, size: CGSize) -> CGImage? {
if let color = blendColor {
setFillColor(color.cgColor)
setBlendMode(blendMode)
fill(CGRect(origin: .zero, size: size))
}
return makeImage()
}
}

View File

@@ -0,0 +1,66 @@
//
// CGImage+Accelerate.swift
// DynamicBlurView
//
// Created by Kyohei Ito on 2017/08/17.
// Copyright © 2017 kyohei_ito. All rights reserved.
//
import Accelerate
import UIKit
extension CGImage {
var area: Int {
return width * height
}
private var size: CGSize {
return CGSize(width: width, height: height)
}
private var bytes: Int {
return bytesPerRow * height
}
private func imageBuffer(from data: UnsafeMutableRawPointer!) -> vImage_Buffer {
return vImage_Buffer(data: data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
}
func blurred(with boxSize: UInt32, iterations: Int, blendColor: UIColor?, blendMode: CGBlendMode) -> CGImage? {
guard let providerData = dataProvider?.data else {
return nil
}
let inData = malloc(bytes)
var inBuffer = imageBuffer(from: inData)
let outData = malloc(bytes)
var outBuffer = imageBuffer(from: outData)
let tempSize = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend + kvImageGetTempBufferSize))
let tempData = malloc(tempSize)
defer {
free(inData)
free(outData)
free(tempData)
}
let source = CFDataGetBytePtr(providerData)
memcpy(inBuffer.data, source, bytes)
for _ in 0..<iterations {
vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, tempData, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend))
let temp = inBuffer.data
inBuffer.data = outBuffer.data
outBuffer.data = temp
}
let context = colorSpace.flatMap {
CGContext(data: inBuffer.data, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: $0, bitmapInfo: bitmapInfo.rawValue)
}
return context?.makeImage(with: blendColor, blendMode: blendMode, size: size)
}
}

View File

@@ -0,0 +1,34 @@
//
// CaptureQuality.swift
// DynamicBlurView
//
// Created by Kyohei Ito on 2017/08/17.
// Copyright © 2017 kyohei_ito. All rights reserved.
//
import UIKit
public enum CaptureQuality {
case `default`
case low
case medium
case high
var imageScale: CGFloat {
switch self {
case .default, .high:
return 0
case .low, .medium:
return 1
}
}
var interpolationQuality: CGInterpolationQuality {
switch self {
case .default, .low:
return .none
case .medium, .high:
return .default
}
}
}

View File

@@ -0,0 +1,19 @@
//
// DynamicBlurView.h
// DynamicBlurView
//
// Created by Kyohei Ito on 2015/04/08.
// Copyright (c) 2015年 kyohei_ito. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for DynamicBlurView.
FOUNDATION_EXPORT double DynamicBlurViewVersionNumber;
//! Project version string for DynamicBlurView.
FOUNDATION_EXPORT const unsigned char DynamicBlurViewVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <DynamicBlurView/PublicHeader.h>

View File

@@ -0,0 +1,195 @@
//
// DynamicBlurView.swift
// DynamicBlurView
//
// Created by Kyohei Ito on 2015/04/08.
// Copyright (c) 2015 kyohei_ito. All rights reserved.
//
import UIKit
open class DynamicBlurView: UIView {
open override class var layerClass : AnyClass {
return BlurLayer.self
}
private var staticImage: UIImage?
private var displayLink: CADisplayLink?
private var blurLayer: BlurLayer {
return layer as! BlurLayer
}
private let mainQueue = DispatchQueue.main
private let globalQueue: DispatchQueue = {
if #available (iOS 8.0, *) {
return .global(qos: .userInteractive)
} else {
return .global(priority: .high)
}
}()
private var renderingTarget: UIView? {
if isDeepRendering {
return window
} else {
return superview
}
}
/// When true, it captures displays image and blur it asynchronously. Try to set true if needs more performance.
/// Asynchronous drawing is possibly crash when needs to process on main thread that drawing with animation for example.
open var drawsAsynchronously: Bool = false
/// Radius of blur.
open var blurRadius: CGFloat {
set { blurLayer.blurRadius = newValue }
get { return blurLayer.blurRadius }
}
/// Default is none.
open var trackingMode: TrackingMode = .none {
didSet {
if trackingMode != oldValue {
linkForDisplay()
}
}
}
/// Blend color.
open var blendColor: UIColor?
/// Blend mode.
open var blendMode: CGBlendMode = .plusLighter
/// Default is 3.
open var iterations: Int = 3
/// If the view want to render beyond the layer, should be true.
open var isDeepRendering: Bool = false
/// When none of tracking mode, it can change the radius of blur with the ratio. Should set from 0 to 1.
open var blurRatio: CGFloat = 1 {
didSet {
if let image = staticImage, oldValue != blurRatio {
draw(image, blurRadius: blurRadius, fixes: false, baseLayer: renderingTarget?.layer)
}
}
}
/// Quality of captured image.
open var quality: CaptureQuality = .medium
public override init(frame: CGRect) {
super.init(frame: frame)
isUserInteractionEnabled = false
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
isUserInteractionEnabled = false
}
open override func didMoveToWindow() {
super.didMoveToWindow()
if let view = renderingTarget, window != nil && trackingMode == .none {
staticImage = snapshotImage(for: view.layer, conversion: !isDeepRendering)
}
}
open override func didMoveToSuperview() {
super.didMoveToSuperview()
if superview == nil {
displayLink?.invalidate()
displayLink = nil
} else {
linkForDisplay()
}
}
private func async(on queue: DispatchQueue, actions: @escaping () -> Void) {
if drawsAsynchronously {
queue.async(execute: actions)
} else {
actions()
}
}
private func sync(on queue: DispatchQueue, actions: () -> Void) {
if drawsAsynchronously {
queue.sync(execute: actions)
} else {
actions()
}
}
private func draw(_ image: UIImage, blurRadius radius: CGFloat, fixes isFixes: Bool, baseLayer: CALayer?) {
async(on: globalQueue) { [weak self] in
if let me = self, let blurredImage = image.blurred(radius: radius, iterations: me.iterations, ratio: me.blurRatio, blendColor: me.blendColor, blendMode: me.blendMode) {
me.sync(on: me.mainQueue) {
me.blurLayer.draw(blurredImage, fixes: isFixes, baseLayer: baseLayer)
}
}
}
}
private func blurLayerRect(to layer: CALayer, conversion: Bool) -> CGRect {
if conversion {
let presentationLayer = blurLayer.presentation() ?? blurLayer
return presentationLayer.convert(presentationLayer.bounds, to: layer)
} else {
return layer.bounds
}
}
private func snapshotImage(for layer: CALayer, conversion: Bool) -> UIImage? {
let rect = blurLayerRect(to: layer, conversion: conversion)
guard let context = CGContext.imageContext(with: quality, rect: rect, opaque: isOpaque) else {
return nil
}
blurLayer.render(in: context, for: layer)
defer {
UIGraphicsEndImageContext()
}
return UIGraphicsGetImageFromCurrentImageContext()
}
}
extension DynamicBlurView {
open override func display(_ layer: CALayer) {
let blurRadius = blurLayer.presentationRadius
let isFixes = isDeepRendering && staticImage != nil
if let view = renderingTarget, let image = staticImage ?? snapshotImage(for: view.layer, conversion: !isFixes) {
draw(image, blurRadius: blurRadius, fixes: isFixes, baseLayer: view.layer)
}
}
}
extension DynamicBlurView {
private func linkForDisplay() {
displayLink?.invalidate()
displayLink = UIScreen.main.displayLink(withTarget: self, selector: #selector(DynamicBlurView.displayDidRefresh(_:)))
displayLink?.add(to: .main, forMode: RunLoop.Mode(rawValue: trackingMode.description))
}
@objc private func displayDidRefresh(_ displayLink: CADisplayLink) {
display(layer)
}
}
extension DynamicBlurView {
/// Remove cache of blur image then get it again.
open func refresh() {
blurLayer.refresh()
staticImage = nil
blurRatio = 1
display(layer)
}
/// Remove cache of blur image.
open func remove() {
blurLayer.refresh()
staticImage = nil
blurRatio = 1
layer.contents = nil
}
/// Should use when needs to change layout with animation when is set none of tracking mode.
public func animate() {
blurLayer.animate()
}
}

View File

@@ -0,0 +1,27 @@
//
// TrackingMode.swift
// DynamicBlurView
//
// Created by Kyohei Ito on 2017/08/17.
// Copyright © 2017 kyohei_ito. All rights reserved.
//
import UIKit
public enum TrackingMode: CustomStringConvertible {
case tracking
case common
case none
public var description: String {
switch self {
case .tracking:
return RunLoop.Mode.tracking.rawValue
case .common:
return RunLoop.Mode.common.rawValue
case .none:
return ""
}
}
}

View File

@@ -0,0 +1,30 @@
//
// UIImage+Blur.swift
// DynamicBlurView
//
// Created by Kyohei Ito on 2017/08/11.
// Copyright © 2017 kyohei_ito. All rights reserved.
//
import UIKit
public extension UIImage {
func blurred(radius: CGFloat, iterations: Int, ratio: CGFloat, blendColor color: UIColor?, blendMode mode: CGBlendMode) -> UIImage? {
guard let cgImage = cgImage else {
return nil
}
if cgImage.area <= 0 || radius <= 0 {
return self
}
var boxSize = UInt32(radius * scale * ratio)
if boxSize % 2 == 0 {
boxSize += 1
}
return cgImage.blurred(with: boxSize, iterations: iterations, blendColor: color, blendMode: mode).map {
UIImage(cgImage: $0, scale: scale, orientation: imageOrientation)
}
}
}