iOS Swift 界面UI相關(guān)

控制器相關(guān)

導(dǎo)航欄

  • 導(dǎo)航欄跟隨右滑手勢返回
// 第一個ViewController
override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    // 這里一定要使用這個方法 否則會有問題
    self.navigationController?.setNavigationBarHidden(true, animated: true)
}

// 第二個ViewController
override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.setNavigationBarHidden(false, animated: true)
}
  • 導(dǎo)航欄設(shè)置中間View
self.navigationItem.titleView = customView;
  • present時設(shè)置全屏
// Swift
navigationController.modalPresentationStyle = .fullScreen
// OC
navigationController.modalPresentationStyle = UIModalPresentationFullScreen;

TabbarController

push跳轉(zhuǎn)時隱藏tabbar

let nextVC = ALCourseListViewController()
nextVC.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(nextVC, animated: true)

 // 這樣back回來的時候振湾,tabBar會恢復(fù)正常顯示
 self.hidesBottomBarWhenPushed = false

修改tabbar圖片和文字的顏色

self.tabBar.tintColor = UIColor.black

修改tabbar整體的背景色

self.tabBar.barTintColor = .white

設(shè)置tabbaritem的內(nèi)容

meNav.tabBarItem.title = ALTool.localizedString("mine")
meNav.tabBarItem.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.systemFont(ofSize: 11)], for: .normal)
meNav.tabBarItem.titlePositionAdjustment = UIOffset.init(horizontal: 0, vertical: -6)
// 使用alwaysOriginal渣淤,強(qiáng)制渲染原圖戚丸。不使用tintColor覆蓋孩等。
meNav.tabBarItem.image = ALUIImage(named: "icon_tab_mine_gray")?.withRenderingMode(.alwaysOriginal)
meNav.tabBarItem.selectedImage = ALUIImage(named: "icon_tab_mine_light")?.withRenderingMode(.alwaysOriginal)
meNav.tabBarItem.tag = 2

// 設(shè)置tabbar項(xiàng)幕屹,并制定默認(rèn)顯示位置
self.setViewControllers([nav0, nav1, meNav], animated: false)
self.selectedIndex = 0

跳轉(zhuǎn)storyboard關(guān)聯(lián)的VC

// xxx 是UIStoryboard的名字满葛,不帶后綴昌罩;xxxVC 是視圖中Identity的StoryboardID
let destinationStoryboard = UIStoryboard(name:"xxx",bundle:nil)
let destinationViewController = destinationStoryboard.instantiateViewController(withIdentifier: "xxxVC") as! XXXViewController
self.navigationController?.pushViewController(destinationViewController, animated: true)

參考文獻(xiàn):
swift 使用多個storyBoard,進(jìn)行視圖跳轉(zhuǎn)

頂部切換tab

黑色模式鎖定

在target的info 中添加 User Interface Style 值為 LightDark

狀態(tài)欄

  • 隱藏狀態(tài)欄
  1. 全局設(shè)置
    在target的info中加入View controller-based status bar appearance值為NO


    再將General->Deployment Info中的Hide status bar 勾選

  2. 在視圖控制器中單獨(dú)設(shè)置
    這種方法適合于只隱藏部分頁面的狀態(tài)欄阱穗。我們在需要隱藏 statusbar 的 ViewController 中添加如下代碼即可饭冬。

override var prefersStatusBarHidden: Bool {
    return false
}

調(diào)節(jié)狀態(tài)欄顏色

在target的info中加入View controller-based status bar appearance值為YES

在ViewController中,重寫以下方法即可

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .default   // 默認(rèn)為黑色揪阶;lightContent:iOS 7.0以上可用昌抠,白色;darkContent:iOS13.0以上可用鲁僚,黑色炊苫;
}

View相關(guān)

webView相關(guān)

  • UIWebView 替換為 WKWebView

UIWebView:

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error API_DEPRECATED("No longer supported.", ios(2.0, 12.0));

WKWebView:

- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;

UIAlertController

  • 文本對齊方式
let subView1:UIView = alert.view.subviews[0]
let subView2 = subView1.subviews[0];
let subView3 = subView2.subviews[0];
let subView4 = subView3.subviews[0];
let subView5 = subView4.subviews[0];
//取title和message:
let title:UILabel = subView5.subviews[1] as! UILabel
let message:UILabel = subView5.subviews[2] as! UILabel
message.textAlignment = .left  // 修改副標(biāo)題對齊方式
title.textAlignment = .center  // 修改主標(biāo)題對齊方式

參考文獻(xiàn):
http://www.reibang.com/p/51a7896d8f1c

UITextView

  • 設(shè)置placeHolder

一個包含placeholder的自定義UITextView

import UIKit

class CustomTextView: UITextView {

    lazy var placeHolderLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.backgroundColor = .clear
        label.alpha = 0
        label.tag = 999
        label.lineBreakMode = .byWordWrapping
        return label
    }()
    
    public var placeholder = ""
    
    public var placeholderColor = UIColor.init(white: 0.8, alpha: 1)
    
    init(frame: CGRect) {
        super.init(frame: frame, textContainer: nil)
        self.delegate = self
        
        self.addSubview(placeHolderLabel)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect: CGRect) {
        placeHolderLabel.frame = CGRect.init(x: 8, y: 8, width: self.bounds.size.width - 16, height: 0)
        placeHolderLabel.font = self.font
        placeHolderLabel.textColor = self.placeholderColor
        if placeholder.count > 0 {
            placeHolderLabel.text = placeholder
            placeHolderLabel.sizeToFit()
            self.sendSubviewToBack(placeHolderLabel)
        }
        if self.text.count == 0 && placeholder.count > 0 {
            self.viewWithTag(CWTagListManager.CustomTextViewTag)?.alpha = 1
        }
        
        super.draw(rect)
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }

}

extension CustomTextView: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        if placeholder.count == 0 {
            return
        }
        if self.text.count == 0 {
            self.viewWithTag(999)?.alpha = 1
        } else {
            self.viewWithTag(999)?.alpha = 0
        }
    }
}

UIButton

  • 文字換行
button.titleLabel?.numberOfLines = 0
button.titleLabel?.lineBreakMode = .byWordWrapping
  • 左對齊
btn.contentHorizontalAlignment = .left

UILabel

  • 富文本設(shè)置行間距
let label = UILabel(frame:CGRect(x:10, y:20, width:300, height:100))
//設(shè)置允許換行
label.numberOfLines = 0
//要顯示的文字
let str = "階段\n測試"
//通過富文本來設(shè)置行間距
let paraph = NSMutableParagraphStyle()
//將行間距設(shè)置為20
paraph.lineSpacing = 20
//樣式屬性集合
let attributes = [NSAttributedString.Key.paragraphStyle: paraph]
label.attributedText = NSAttributedString(string: str, attributes: attributes)
self.view.addSubview(label)

參考文獻(xiàn):
UIButton 文字換行的一種方案

UIScrollView

  • 滑動到邊界后,不允許繼續(xù)拖動
scrollView.bounces = false
  • 頂部有空白解決方法
if #available(iOS 11.0, *) {
    self.contentInsetAdjustmentBehavior = .never
} else {
    // Fallback on earlier versions
}

UITableView相關(guān)

UICollectionView相關(guān)

關(guān)于viewWithTag的坑

1冰沙、superview可以viewWithTag直接訪問到subview中對應(yīng)tag的控件侨艾,所以如果要標(biāo)記一個控件時,同一個superview下的subview拓挥,注意不要有存在沖突的相同tag的控件唠梨,建議根據(jù)view級數(shù)來定義,比如superview級的tag用100X,子View用200x侥啤,孫view用300x当叭,依次類推。
2愿棋、如果父view的tag和子view一樣科展,viewWithTag得到的會是父view,因?yàn)関iewWithTag得到的是最先設(shè)置tag為2000的那個控件(包含父view和子view)糠雨。

參考文獻(xiàn):
http://www.reibang.com/p/5040b6e0f5a0

CAShapeLayer和UIBezierPath

CAShapeLayer 是CALayer 的子類才睹。

let layer = CAShapeLayer()
layer.fillColor = UIColor.clear.cgColor
layer.strokeColor = CWCustomColor.colorWithRGB(red: 253, green: 198, blue: 81).cgColor
layer.lineWidth = 5
layer.lineJoin = .round
layer.lineCap = .round
layer.isHidden = true

CAShapeLayer 有一個特別好用的屬性,path。我們可以里用 UIBezierPath & CAShapeLayer的 .path 屬性琅攘,畫出我們?nèi)我庀M@示的圖形垮庐。并且搭配 CAShapeLayer 的 strokeBegin & strokeEnd 屬性∥肭伲可以做出一些比較炫酷的圖形動畫效果哨查。

UIBezierPath 專門是用來繪制路徑的,常和CAShapeLayer一起配合使用剧辐。

/// 使用路徑繪制 CAShape
/// 因?yàn)橛玫搅?貝塞爾曲線寒亥,所以就可以使用核心繪圖的一些參數(shù)。
/// 比如荧关,線寬溉奕、描邊、填充等忍啤。
func shapeLayerUserPath() {
    let shapeLayer = CAShapeLayer()
    // 創(chuàng)建路徑
    let path = UIBezierPath()
    path.move(to: CGPoint(x: 10, y: 80))
    path.addLine(to: CGPoint(x: 100, y: 80))
    path.addLine(to: CGPoint(x: 100, y: 180))
    path.addLine(to: CGPoint(x: 10, y: 180))
    path.addLine(to: CGPoint(x: 10, y: 80))
    // [path closePath]; // 閉合路徑
    // 設(shè)置 CAShapeLayer 的繪制路徑
    shapeLayer.path = path.cgPath

    // 有路徑了加勤,就可以設(shè)置填充顏色,線的樣式同波,描邊顏色等鳄梅。
    shapeLayer.strokeColor = UIColor.purple.cgColor
    // CAShapeLayer 如果是閉合路徑,那么默認(rèn)的填充顏色是黑色未檩。
    // shapeLayer.fillColor = [UIColor orangeColor].CGColor;
    shapeLayer.fillColor = UIColor.white.cgColor
    shapeLayer.lineWidth = 10 // 線寬
    shapeLayer.lineJoin = CAShapeLayerLineJoin(rawValue: "round") // 線頭樣式
    shapeLayer.lineCap = CAShapeLayerLineCap(rawValue: "round") // 折現(xiàn)結(jié)合處樣式

    view.layer.addSublayer(shapeLayer)
}

運(yùn)行效果:



當(dāng)然戴尸,UIBezierPath 能夠畫出什么圖形,那么 CAShapeLayer 就能顯示出多少中圖形讹挎。

  1. 畫曲線
private func addShareLayer() {
    let layer = CAShapeLayer()
    let path = UIBezierPath()
    
    // 畫一條貝塞爾曲線
    path.move(to: CGPoint.init(x: 0, y: UIScreen.main.bounds.height * 0.5 + 100))
    path.addQuadCurve(to: CGPoint.init(x: UIScreen.main.bounds.width, y: UIScreen.main.bounds.height * 0.5 + 100), controlPoint: CGPoint.init(x: view.center.x, y: view.center.y))
    
    // 設(shè)置曲線到 CAShapeLayer 的 path
    layer.path = path.cgPath
    
    // 實(shí)現(xiàn)線的基本屬性
    layer.strokeColor = UIColor.purple.cgColor
    layer.lineWidth = 5
    layer.lineCap = .round
    layer.fillColor = UIColor.white.cgColor
    self.view.layer.addSublayer(layer)
}

運(yùn)行效果:


曲線

使用 CAShapeLayer 以動畫的方式繪制圖形
由于 CAShapeLayer 繼承自 CALayer校赤。CALayer 有可以搭配 CAAnimation 使用。所以可以使用 CAShapeLayer & UIBezierPath & CAAnimation 來產(chǎn)生比較酷炫的動畫效果筒溃。
主要是搭配 CAShapeLayer 的 strokeStart & strokeEnd 來實(shí)現(xiàn)比較炫酷的效果。

private func shapeLayerDrawRect() {
    let layer = CAShapeLayer()
    let path = UIBezierPath.init(rect: CGRect.init(x: 10, y: 200, width: 100, height: 100))
    
    layer.path = path.cgPath
    
    layer.strokeColor = UIColor.orange.cgColor
    layer.fillColor = UIColor.white.cgColor
    layer.lineWidth = 3
    layer.lineCap = .round
    
    self.view.layer.addSublayer(layer)
    
    let anim = CABasicAnimation.init(keyPath: "strokeEnd")
    anim.fromValue = 0
    anim.toValue = 1
    anim.repeatCount = MAXFLOAT
    anim.duration = 3
    anim.fillMode = .forwards
    anim.isRemovedOnCompletion = false
    
    layer.add(anim, forKey: nil)
}

運(yùn)行效果:

矩形動畫

使用場景:
可以利用 CAShapeLayer 的動畫特性做一些提示類的動畫沾乘。由于 CAShapeLayer 不是 UIResponder 怜奖,所以,它不能接受事件翅阵。
它的作用歪玲,就是展示,也僅僅是展示掷匠。
可以利用 CAShapeLayer 的路徑動畫特性滥崩,做一些有功能性的動畫。例如:選擇答案后顯示對勾錯誤讹语。效果和代碼可以在CAShapeLayer 初探文章中查看钙皮。

參考文獻(xiàn):
Core Graphics 之 路徑的填充規(guī)則與混合模式
CAShapeLayer 初探

CAShapeLayer和DrawRect

  • DrawRect:DrawRect屬于CoreGraphic框架,占用CPU,消耗性能大
  • CAShapeLayer:CAShapeLayer屬于CoreAnimation框架短条,通過GPU來渲染圖形导匣,節(jié)省性能。動畫渲染直接提交給手機(jī)GPU茸时,不消耗內(nèi)存
override func draw(_ rect: CGRect) {
    // 獲取當(dāng)前的圖形上下文
    let context = UIGraphicsGetCurrentContext()
    
    // 設(shè)置線條的屬性
    // 1.設(shè)置線寬
    context?.setLineWidth(lineWidth_p_DP)
    // 2.設(shè)置線條的顏色
    context?.setStrokeColor(UIColor.brown.cgColor)
    // 3.填充顏色
    context?.setFillColor(UIColor.brown.cgColor) 
    // 開始畫線,需要將起點(diǎn)移動到指定的point
    context?.move(to: firstPoint_p_DP)
    // 添加一根線到另一個點(diǎn) (兩點(diǎn)一線)
    context?.addLine(to: secondPoint_p_DP)
    context?.addLine(to: thirdPoint_p_DP)
    // 閉合路徑,連線結(jié)束后會把起點(diǎn)和終點(diǎn)連起來
    context?.closePath() 
    // 奇偶規(guī)則:從路徑覆蓋范圍內(nèi)的任意一點(diǎn)做一條射線(確保這條射線的長度要比路徑覆蓋范圍要大) , 如果與該射線相交的邊的數(shù)量為奇數(shù), 則該點(diǎn)是路徑的內(nèi)部點(diǎn), 反之該點(diǎn)則是路徑的外部點(diǎn)贡定。
    // 非零環(huán)繞數(shù)原則:首先定義一個用于焦點(diǎn)統(tǒng)計的count值,然后從路徑覆蓋范圍內(nèi)的任意一點(diǎn)做一條射線(確保這條射線的長度要比路徑覆蓋范圍要大). 然后我們對每一條和該射線相交的路徑進(jìn)行統(tǒng)計, 統(tǒng)計規(guī)則是這樣的: 當(dāng)路徑是從右向左穿過射線的時候, count++, 當(dāng)路徑是從左向右穿過射線的時候, count--. 當(dāng)我們統(tǒng)計完所有相交的路徑后, 如果 count不為0, 則該點(diǎn)是內(nèi)部點(diǎn), 該點(diǎn)所在的封閉區(qū)域需要填充, 反之該點(diǎn)則是路徑的外部點(diǎn)
    // 混合模式:混合模式是指在進(jìn)行繪制時如何使用繪制背景的方式可都!Quartz2D中使用默認(rèn)的混合方式缓待,并使用以下公式將背景畫和前景畫進(jìn)行結(jié)合:result = (alpha * foreground) + (1 - alpha) * background 、alpha表示顏色的不透明值
    // 使用CGPathDrawingMode繪制模式繪制當(dāng)前路徑(fill :使用非零環(huán)繞路徑渲染規(guī)則渠牲;eoFill:奇偶渲染規(guī)則命斧;stroke:沿著路徑渲染一條線;fillStroke:先按照非零環(huán)繞進(jìn)行填充然后進(jìn)行繪制路徑嘱兼;eoFillStroke:先按照奇偶規(guī)則填充国葬,然后進(jìn)行繪制路徑)
    mainPath?.drawPath(using: .fillStroke)
    // 使用CGPathFillRule填充規(guī)則(winding 非零環(huán)繞規(guī)則;evenOdd 奇偶規(guī)則)
    mainPath?.fillPath(using: .winding)
    // 渲染圖形到上下文
    context?.strokePath()
}

參考文獻(xiàn):
iOS CAShapeLayer 使用

layoutSubviews和drawRect

一芹壕、layoutSubviews在以下情況下會被調(diào)用:
1汇四、init初始化不會觸發(fā)layoutSubviews。
2踢涌、addSubview會觸發(fā)layoutSubviews通孽。
3、改變一個UIView的Frame會觸發(fā)layoutSubviews睁壁,當(dāng)然前提是frame的值設(shè)置前后發(fā)生了變化背苦。
4、滾動一個UIScrollView引發(fā)UIView的重新布局會觸發(fā)layoutSubviews潘明。
5行剂、旋轉(zhuǎn)Screen會觸發(fā)父UIView上的layoutSubviews事件。
6钳降、直接調(diào)用setNeedsLayout 或者 layoutIfNeeded厚宰。

二、drawRect在以下情況下會被調(diào)用:
1遂填、如果在UIView初始化時沒有設(shè)置rect大小铲觉,將直接導(dǎo)致drawRect不被自動調(diào)用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 兩方法之后掉用的.所以不用擔(dān)心在 控制器中,這些View的drawRect就開始畫了.這樣可以在控制器中設(shè)置一些值給View(如果這些View draw的時候需要用到某些變量值).
2吓坚、該方法在調(diào)用sizeToFit后被調(diào)用撵幽,所以可以先調(diào)用sizeToFit計算出size。然后系統(tǒng)自動調(diào)用drawRect:方法礁击。
3盐杂、通過設(shè)置contentMode屬性值為UIViewContentModeRedraw逗载。那么將在每次設(shè)置或更改frame的時候自動調(diào)用drawRect:。
4况褪、直接調(diào)用setNeedsDisplay撕贞,或者setNeedsDisplayInRect:觸發(fā)drawRect:,但是有個前提條件是rect不能為0测垛。
以上1,2推薦捏膨;而3,4不提倡

參考文獻(xiàn):
https://blog.csdn.net/wangyanchang21/article/details/50774522

離屏渲染

油畫算法

圖層的繪制,遵循油畫算法食侮。即按層繪制号涯。先繪制距離較遠(yuǎn)的場景,再繪制較近的場景并覆蓋較遠(yuǎn)的部分锯七。如下圖

油畫算法

這樣就不會使較遠(yuǎn)的物體擋住較近的物體链快。但是有一個局限,就是無法在較近的一層渲染完后眉尸,再回去修改較遠(yuǎn)的圖層域蜗,因?yàn)檩^遠(yuǎn)的圖層已經(jīng)被覆蓋了。這時候就涉及到了離屏渲染噪猾。

離屏渲染

對于上述有前后依賴的圖層(如全局剪切霉祸,陰影等),油畫算法無法滿足袱蜡。這時可以另開辟一個空間丝蹭,用于臨時渲染,渲染完成后再渲染到當(dāng)前的緩沖區(qū)上坪蚁。這個臨時渲染奔穿,就是離屏渲染
因?yàn)殡x屏渲染敏晤,需要開辟新的空間贱田,并且共享同一個上下文,還需要做上下文切換茵典,并且渲染完后還要進(jìn)行拷貝操作湘换。所以會消耗一定的資源,當(dāng)離屏渲染過多時统阿,則會導(dǎo)致GPU渲染時間過長而發(fā)生卡頓,所以應(yīng)該避免離屏渲染筹我。

如何避免離屏渲染

若想避免離屏渲染扶平,首先要知道如何檢測離屏渲染。在Simulator的Debug中打開Color Off-screen Rendered蔬蕊。

// 1. UIImageView
let imageView = UIImageView(frame: CGRect(x: 50, y: 100, width: 300, height: 200))
self.view.addSubview(imageView)
imageView.image = UIImage.init(named: "test.jpg")

// image + cornerRadius + masksToBounds 不會觸發(fā)離屏渲染
imageView.layer.cornerRadius = 10
imageView.layer.masksToBounds = true

// 觸發(fā)離屏渲染
imageView.backgroundColor = UIColor.green
// 添加一個空的UIView不會觸發(fā)離屏渲染
// imageView.addSubview(UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10)))

// 2. UIButton
let button = UIButton(type: .custom)
button.frame = CGRect(x: 50, y: 300 + 50, width: 300, height: 50)
self.view.addSubview(button)
button.setTitle("Test", for: .normal)
button.setTitleColor(UIColor.blue, for: .normal)
button.layer.cornerRadius = 10
button.layer.masksToBounds = true

// 觸發(fā)離屏渲染
button.backgroundColor = UIColor.green
// 觸發(fā)離屏渲染
button.setBackgroundImage(UIImage(named: "test.jpg"), for: .normal)

// 3. UIView
let view = UIView(frame: CGRect(x: 50, y: 400 + 50, width: 300, height: 50))
self.view.addSubview(view)
view.backgroundColor = UIColor.red
view.layer.cornerRadius = 10
view.layer.masksToBounds = true

// label如果被渲染结澄,則會觸發(fā)渲染哥谷,如果text為空不會被渲染
let label = UILabel(frame: CGRect(x: 10, y: 10, width: 1, height: 1))
label.text = "1"
view.addSubview(label)
離屏渲染的區(qū)域?yàn)辄S色

根據(jù)上述方法測試,可以得到是否觸發(fā)離屏渲染的情況:
設(shè)置了cornerRadious+masksToBounds的:

  • UIImageView設(shè)置圖片麻献,不會觸發(fā)们妥;
  • UIView設(shè)置背景顏色,如果沒有subViews勉吻,不會觸發(fā)监婶;
  • UILabel設(shè)置文字,且設(shè)置backgroundColor齿桃,會觸發(fā)惑惶;
  • UIButton設(shè)置文字和背景,會觸發(fā)短纵;
    其他會觸發(fā)離屏渲染的情況:
  • 使用了遮罩的layer(layer.mask)
  • 需要進(jìn)行裁剪的layer(layer.masksToBounds / view.clipsToBounds)
  • 設(shè)置了組透明度為 YES带污,并且透明度不為 1 的layer (layer.allowsGroupOpacity / layer.opacity)
  • 添加了投影的 layer (layer.shadow),但如果設(shè)置了shadowPath香到,則系統(tǒng)已經(jīng)知道如何繪制陰影了鱼冀,不會觸發(fā)離屏渲染
  • 采用了光柵化的 layer (layer.shouldRasterize),光柵化也可以優(yōu)化離屏渲染問題
  • 繪制了文字的 layer (UILabel, CATextLayer, CoreText等)
  • 使用了毛玻璃/高斯模糊
優(yōu)化離屏渲染問題

1悠就、避免使用裁切(masksToBounds)方式千绪,如果確保內(nèi)容不會溢出,則不宜使用masksToBounds理卑;
2翘紊、必須使用裁切時,盡量用最外層的view去裁切藐唠。因?yàn)椴们行枰獙λ械膌ayer和subviews所有圖層進(jìn)行裁切帆疟,越內(nèi)層的view,離屏渲染所需要的空間越大宇立。
3踪宠、提前切好需要的圓角,避免需要的時候再切妈嘹。

參考文獻(xiàn):
https://blog.bombox.org/2020-07-14/ios-offscreen-render/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柳琢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子润脸,更是在濱河造成了極大的恐慌柬脸,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毙驯,死亡現(xiàn)場離奇詭異倒堕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)爆价,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門垦巴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來媳搪,“玉大人,你說我怎么就攤上這事骤宣∏乇” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵憔披,是天一觀的道長等限。 經(jīng)常有香客問我,道長活逆,這世上最難降的妖魔是什么精刷? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮蔗候,結(jié)果婚禮上怒允,老公的妹妹穿的比我還像新娘。我一直安慰自己锈遥,他們只是感情好纫事,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著所灸,像睡著了一般丽惶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上爬立,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天钾唬,我揣著相機(jī)與錄音,去河邊找鬼侠驯。 笑死抡秆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吟策。 我是一名探鬼主播儒士,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼檩坚!你這毒婦竟也來了着撩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤匾委,失蹤者是張志新(化名)和其女友劉穎拖叙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赂乐,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡憋沿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了沪猴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辐啄。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖运嗜,靈堂內(nèi)的尸體忽然破棺而出壶辜,到底是詐尸還是另有隱情,我是刑警寧澤担租,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布砸民,位于F島的核電站,受9級特大地震影響奋救,放射性物質(zhì)發(fā)生泄漏岭参。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一尝艘、第九天 我趴在偏房一處隱蔽的房頂上張望演侯。 院中可真熱鬧,春花似錦背亥、人聲如沸秒际。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娄徊。三九已至,卻和暖如春盾戴,著一層夾襖步出監(jiān)牢的瞬間寄锐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工尖啡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橄仆,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓可婶,卻偏偏與公主長得像沿癞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子矛渴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350