Swift设置基于内容偏移的Scrollview子视图帧位置
问题:Swift设置基于内容偏移的Scrollview子视图帧位置,swift,uiscrollview,Swift,Uiscrollview,问题: `func scrollViewDidScroll(_ scrollView: UIScrollView) { items.enumerated().forEach { (index, tabView) in let screenWidth = UIScreen.main.bounds.width // This returns a value between 0 and 1 depending on the location o
`func scrollViewDidScroll(_ scrollView: UIScrollView) {
items.enumerated().forEach { (index, tabView) in
let screenWidth = UIScreen.main.bounds.width
// This returns a value between 0 and 1 depending on the location of the tab view within the visible screen
let xOffset = scrollView.convert(CGPoint(x: tabView.frame.minX, y: 0), to: view).x
let percentViewMovedOnVisibleScreen: CGFloat = xOffset / screenWidth
// Spacing - NOT CORRECT
let someSpacingAmount: CGFloat = 80
tabView.frame.origin.x = CGFloat(index) * percentViewMovedOnVisibleScreen * someSpacingAmount
}
}`
我正在重新创建iPhone应用程序切换器页面,在该页面中,应用程序视图在屏幕左侧彼此重叠。看起来每个应用程序视图框架的x位置是根据其在可见屏幕上的索引和位置设置的
我有一个滚动视图中的视图数组。如何设置视图框架以复制iPhone应用程序切换页面
尝试:
`func scrollViewDidScroll(_ scrollView: UIScrollView) {
items.enumerated().forEach { (index, tabView) in
let screenWidth = UIScreen.main.bounds.width
// This returns a value between 0 and 1 depending on the location of the tab view within the visible screen
let xOffset = scrollView.convert(CGPoint(x: tabView.frame.minX, y: 0), to: view).x
let percentViewMovedOnVisibleScreen: CGFloat = xOffset / screenWidth
// Spacing - NOT CORRECT
let someSpacingAmount: CGFloat = 80
tabView.frame.origin.x = CGFloat(index) * percentViewMovedOnVisibleScreen * someSpacingAmount
}
}`
我认为这很接近,但它并不能让你完全了解苹果拥有的东西。也许除了didScroll之外,还需要一些别的东西来使它感觉平滑
GitHub示例项目:很可能(我想说)这不是在滚动视图中完成的
考虑这个例子:
class TestSwitcherViewController: UIViewController {
var leadConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
let colors: [UIColor] = [
// light red
UIColor(red: 1.0, green: 0.5, blue: 0.5, alpha: 1.0),
// light green
UIColor(red: 0.5, green: 1.0, blue: 0.5, alpha: 1.0),
// light blue
UIColor(red: 0.0, green: 0.5, blue: 1.0, alpha: 1.0),
// light orange
UIColor(red: 0.9, green: 0.7, blue: 0.5, alpha: 1.0),
// yellow
UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0),
]
var prevView: UIView!
// create a view for each color (a label with the view number as its text)
// for each of the views
// if it's the first one,
// constrain leading to view leading
// else
// constrain leading to previous view leading, constant 1.0, multiplier 2.0
var i = 1
colors.forEach { c in
let v = UILabel()
v.backgroundColor = c
v.text = "\(i)"
v.textAlignment = .center
v.layer.cornerRadius = 20
v.layer.masksToBounds = true
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
v.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
v.widthAnchor.constraint(equalToConstant: 200.0).isActive = true
v.heightAnchor.constraint(equalToConstant: 400.0).isActive = true
if i == 1 {
leadConstraint = v.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0)
leadConstraint.isActive = true
} else {
NSLayoutConstraint(item: v, attribute: .leading, relatedBy: .equal, toItem: prevView, attribute: .leading, multiplier: 2.0, constant: 1.0).isActive = true
}
prevView = v
i += 1
}
// add a pan gesture recognizer to the view
let pan = UIPanGestureRecognizer(target: self, action: #selector(self.didPan(_:)))
view.addGestureRecognizer(pan)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updateScales()
}
@objc func didPan(_ gesture: UIPanGestureRecognizer) -> Void {
let translation = gesture.translation(in: view)
// increment or decrement the leading anchor constant
let tmpX = leadConstraint.constant + (translation.x * 0.25)
// don't let it go past either side
leadConstraint.constant = min(max(tmpX, 0.0), view.frame.width - 200.0)
gesture.setTranslation(.zero, in: view)
updateScales()
}
func updateScales() -> Void {
view.subviews.forEach { v in
// percentage of distance from leading edge of label to 1/5th width of view
let pct = min(v.frame.origin.x / (view.frame.width * 0.2), 1.0)
let scale = 0.8 + 0.2 * pct
v.transform = .identity
v.transform = CGAffineTransform(scaleX: scale, y: scale)
}
}
}
它将创建5个彩色视图(带编号的标签),并使用带有常量和倍增的前导锚点相互约束。它会向视图添加平移手势,因此当您向左或向右平移时,它会修改“底部”视图的前导约束的常量,以将其向左/向右移动。这将依次移动其他视图。。。由于我们对约束使用了乘数,所以当我们向右滑动时,运动会“增长”
以下是发布时的外观:
下面是向右拖动一点后的外观:
显然,复制应用程序切换器的所有功能需要做更多的工作,但这可能会让您上路。scrollViewDidScroll可以使用。但是你必须要有合适的动画。在AppSwitcher中有几个不同的动画,当应用程序到达屏幕中心时,它的行为不同于它的速度减慢,在最后它会稍微缩小并淡出。因此,您需要处理所有这些情况,并为动画的不同阶段计算不同的帧。此外,应用程序框架是一个接一个的,不像您的示例中那样具有水平间距。而且它们并不是真的只在最后才扩展那么多。由于速度的原因,一切看起来都很好change@GrzegorzKrukowski是的,它需要被分解成碎片。你知道如何根据屏幕上的位置改变间距吗?苹果肯定是在使用滚动视图。他们用减速法总是降落在一个视图上。与使用约束的方式类似,如何在滚动视图中更改视图的x帧?@Ryan-在没有滚动视图的情况下,可以轻松地将视图设置为中心动画。正如我所说,还有很多工作要做。。。这只是以相对速度移动视图的一种方法。你可能想看看。。。“时间机器”效应并不遥远。检查该代码可能会给您一些启发。