UIPickerView 确实按行传递
UIPickerView did pass by row
我有这个演示应用程序:
如您所见,背景的 alpha 正根据该值变为黑色。
但问题是没有平滑过渡:
从动图中可以看出,滚动结束后背景才会发生变化。我不希望它变成那样。
这是我的代码:
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
@IBOutlet weak var pickerView: UIPickerView!
@IBOutlet weak var backView: UIView!
let max = 100
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return max + 1 // To include '0'
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let l = UILabel(frame: .zero)
l.text = String(max - row)
l.textColor = .white
l.font = UIFont.preferredFont(forTextStyle: .title3)
l.textAlignment = .center
return l
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
backView.alpha = CGFloat(max - row) / 100
}
}
我给委托 UIView
而不是字符串,因为我有一个想法:每次每行的位置发生变化时进行测试,当该行位于屏幕中间时我应该更新背景。但不幸的是我不知道该怎么做。
也许你能帮忙?或者提出任何其他想法?
谢谢!
委托方法 didSelectRow
仅在滚动停止时调用,因此这不是您应该更新 alpha 的地方。 UIPickerView
没有委托方法可以在滚动期间通知您有关更改的信息,但是 UIPickerView
将调用您的数据源和委托方法来获取标题,或者在您的情况下是给定行的视图它可以在用户滚动时显示。所以你应该做的就是把你的 alpa 改变逻辑移到那里:
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
backView.alpha = CGFloat(max - row) / 100
}
请注意,此委托方法将在 UIPickerView
加载时调用,因此您可能应该禁用 alpha 更改,直到视图布局不正确(也许 viewDidAppear
会这样做)。
由于委托方法有时会出现意外行为(不仅调用下一行,还调用选取器中的任何一行),我们应该存储并检查该行是否仅比上次保存的值领先或落后一步,否则我们应该忽略它。我做了一个简单的演示来演示它是如何工作的:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
private let pickerView = UIPickerView()
private var isPickerReady = false
private var lastValue = 0
private let max = 100
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(pickerView)
pickerView.translatesAutoresizingMaskIntoConstraints = false
pickerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
pickerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
pickerView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
pickerView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
pickerView.delegate = self
pickerView.dataSource = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
isPickerReady = true
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return max
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
// Do not update the value until the view is not loaded
// Only consider delegate methods which are one step ahead or behind the last value
if row + 1 == lastValue && isPickerReady || row - 1 == lastValue && isPickerReady {
lastValue = row
view.alpha = CGFloat(max - lastValue ) / 100
}
return "Tiltle \(row)"
}
}
我有这个演示应用程序:
如您所见,背景的 alpha 正根据该值变为黑色。
但问题是没有平滑过渡:
从动图中可以看出,滚动结束后背景才会发生变化。我不希望它变成那样。
这是我的代码:
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
@IBOutlet weak var pickerView: UIPickerView!
@IBOutlet weak var backView: UIView!
let max = 100
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return max + 1 // To include '0'
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let l = UILabel(frame: .zero)
l.text = String(max - row)
l.textColor = .white
l.font = UIFont.preferredFont(forTextStyle: .title3)
l.textAlignment = .center
return l
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
backView.alpha = CGFloat(max - row) / 100
}
}
我给委托 UIView
而不是字符串,因为我有一个想法:每次每行的位置发生变化时进行测试,当该行位于屏幕中间时我应该更新背景。但不幸的是我不知道该怎么做。
也许你能帮忙?或者提出任何其他想法?
谢谢!
委托方法 didSelectRow
仅在滚动停止时调用,因此这不是您应该更新 alpha 的地方。 UIPickerView
没有委托方法可以在滚动期间通知您有关更改的信息,但是 UIPickerView
将调用您的数据源和委托方法来获取标题,或者在您的情况下是给定行的视图它可以在用户滚动时显示。所以你应该做的就是把你的 alpa 改变逻辑移到那里:
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
backView.alpha = CGFloat(max - row) / 100
}
请注意,此委托方法将在 UIPickerView
加载时调用,因此您可能应该禁用 alpha 更改,直到视图布局不正确(也许 viewDidAppear
会这样做)。
由于委托方法有时会出现意外行为(不仅调用下一行,还调用选取器中的任何一行),我们应该存储并检查该行是否仅比上次保存的值领先或落后一步,否则我们应该忽略它。我做了一个简单的演示来演示它是如何工作的:
import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
private let pickerView = UIPickerView()
private var isPickerReady = false
private var lastValue = 0
private let max = 100
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(pickerView)
pickerView.translatesAutoresizingMaskIntoConstraints = false
pickerView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
pickerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
pickerView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
pickerView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
pickerView.delegate = self
pickerView.dataSource = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
isPickerReady = true
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return max
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
// Do not update the value until the view is not loaded
// Only consider delegate methods which are one step ahead or behind the last value
if row + 1 == lastValue && isPickerReady || row - 1 == lastValue && isPickerReady {
lastValue = row
view.alpha = CGFloat(max - lastValue ) / 100
}
return "Tiltle \(row)"
}
}