什么是如何实现橡皮筋效果的完整示例? 我该如何实现?
I have tried the following: However, I have been unsuccessful in finding how to implement this.
当前,我创建了一个卡片视图,该视图可以拉至特定点,但是目前,当您达到最大值时,会突然停止,我想更改为橡皮筋效果。
这是我一直在尝试添加的代码:
enum SheetLevel{
case top, bottom, middle
}
protocol BottomSheetDelegate {
func updateBottomSheet(frame: CGRect)
}
class BottomSheetViewController: UIViewController{
@IBOutlet var panView: UIView!
@IBOutlet weak var tableView: UICollectionView!
// @IBOutlet weak var collectionView: UICollectionView! //header view
var lastY: CGFloat = 0
var pan: UIPanGestureRecognizer!
var bottomSheetDelegate: BottomSheetDelegate?
var parentView: UIView!
var initalFrame: CGRect!
var topY: CGFloat = 80 //change this in viewWillAppear for top position
var middleY: CGFloat = 400 //change this in viewWillAppear to decide if animate to top or bottom
var bottomY: CGFloat = 600 //no need to change this
let bottomOffset: CGFloat = 64 //sheet height on bottom position
var lastLevel: SheetLevel = .middle //choose inital position of the sheet
var disableTableScroll = false
//hack panOffset To prevent jump when goes from top to down
var panOffset: CGFloat = 0
var applyPanOffset = false
//tableview variables
var listItems: [Any] = []
var headerItems: [Any] = []
override func viewDidLoad() {
super.viewDidLoad()
pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
pan.delegate = self
self.panView.addGestureRecognizer(pan)
self.tableView.panGestureRecognizer.addTarget(self, action: #selector(handlePan(_:)))
//Bug fix #5. see https://github.com/OfTheWolf/UBottomSheet/issues/5
//Tableview didselect works on second try sometimes so i use here a tap gesture recognizer instead of didselect method and find the table row tapped in the handleTap(_:) method
let tap = UITapGestureRecognizer.init(target: self, action: #selector(handleTap(_:)))
tap.delegate = self
tableView.addGestureRecognizer(tap)
//Bug fix #5 end
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.initalFrame = UIScreen.main.bounds
self.topY = round(initalFrame.height * 0.5)
self.middleY = initalFrame.height * 0.6
self.bottomY = initalFrame.height - bottomOffset
self.lastY = self.middleY
bottomSheetDelegate?.updateBottomSheet(frame: self.initalFrame.offsetBy(dx: 0, dy: self.middleY))
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard scrollView == tableView else {return}
if (self.parentView.frame.minY > topY){
self.tableView.contentOffset.y = 0
}
}
//this stops unintended tableview scrolling while animating to top
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
guard scrollView == tableView else {return}
if disableTableScroll{
targetContentOffset.pointee = scrollView.contentOffset
disableTableScroll = false
}
}
//Bug fix #5. see https://github.com/OfTheWolf/UBottomSheet/issues/5
@objc func handleTap(_ recognizer: UITapGestureRecognizer) {
let p = recognizer.location(in: self.tableView)
//Commented below to prevenet error.. *** apr 2 guillermo
// let index = tableView.indexPathForRow(at: p)
// //WARNING: calling selectRow doesn't trigger tableView didselect delegate. So handle selected row here.
// //You can remove this line if you dont want to force select the cell
// tableView.selectRow(at: index, animated: false, scrollPosition: .none)
}//Bug fix #5 end
@objc func handlePan(_ recognizer: UIPanGestureRecognizer) {
// var x = topY
// var c = 0.55
// var d = view.frame.height
// var formula = (1.0 - (1.0 / ((x * c / d) + 1.0))) * d
let dy = recognizer.translation(in: self.parentView).y
print(recognizer.translation(in: self.parentView).y, " This si dy")
switch recognizer.state {
case .began:
applyPanOffset = (self.tableView.contentOffset.y > 0)
case .changed:
print(".changed here")
if self.tableView.contentOffset.y > 0{
panOffset = dy
return
}
if self.tableView.contentOffset.y <= 0 {
if !applyPanOffset{panOffset = 0}
let maxY = max(topY, lastY + dy - panOffset)
let y = min(bottomY, maxY)
print(y, ".inside if let thindfahfvdsgjafjsda8", maxY)
// self.panView.frame = self.initalFrame.offsetBy(dx: 0, dy: y)
bottomSheetDelegate?.updateBottomSheet(frame: self.initalFrame.offsetBy(dx: 0, dy: y))
}
if self.parentView.frame.minY > topY{
print(self.tableView.contentOffset.y, " Thsi is taht y vakue thing")
self.tableView.contentOffset.y = 0
}
case .failed, .ended, .cancelled:
panOffset = 0
print(".failed and enededh rhere")
//bug fix #6. see https://github.com/OfTheWolf/UBottomSheet/issues/6
if (self.tableView.contentOffset.y > 0){
return
}//bug fix #6 end
self.panView.isUserInteractionEnabled = false
self.disableTableScroll = self.lastLevel != .top
self.lastY = self.parentView.frame.minY
self.lastLevel = self.nextLevel(recognizer: recognizer)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.9, options: .curveEaseOut, animations: {
print("Animation!!!!!")
switch self.lastLevel {
case .top:
print("in this thanaagaggagagagagagagalanfg")
// self.panView.frame = self.initalFrame.offsetBy(dx: 0, dy: self.topY)
// self.bottomSheetDelegate?.updateBottomSheet(frame: self.initalFrame.offsetBy(dx: 0, dy: self.topY))
// self.tableView.contentInset.bottom = 50
self.bottomSheetDelegate?.updateBottomSheet(frame: self.initalFrame.offsetBy(dx: 0, dy: self.middleY))
case .middle:
// self.panView.frame = self.initalFrame.offsetBy(dx: 0, dy: self.middleY)
self.bottomSheetDelegate?.updateBottomSheet(frame: self.initalFrame.offsetBy(dx: 0, dy: self.middleY))
case .bottom:
// self.panView.frame = self.initalFrame.offsetBy(dx: 0, dy: self.bottomY)
self.bottomSheetDelegate?.updateBottomSheet(frame: self.initalFrame.offsetBy(dx: 0, dy: self.bottomY))
}
}) { (_) in
print("Someghtifgnshdfgbk")
self.panView.isUserInteractionEnabled = true
self.lastY = self.parentView.frame.minY
}
default:
break
}
}
func nextLevel(recognizer: UIPanGestureRecognizer) -> SheetLevel{
let y = self.lastY
let velY = recognizer.velocity(in: self.view).y
if velY < -200{
return y > middleY ? .middle : .top
}else if velY > 200{
return y < (middleY + 1) ? .middle : .bottom
}else{
if y > middleY {
return (y - middleY) < (bottomY - y) ? .middle : .bottom
}else{
return (y - topY) < (middleY - y) ? .top : .middle
}
}
}
}
extension BottomSheetViewController: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SimpleTableCell", for: indexPath) as! SimpleTableCell
let model = SimpleTableCellViewModel(image: nil, title: "Title \(indexPath.row)", subtitle: "Subtitle \(indexPath.row)")
cell.configure(model: model)
return cell
}
}
extension BottomSheetViewController: UIGestureRecognizerDelegate{
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
答案 0 :(得分:1)
您需要做的是通过拖动以指数方式减少用户添加的长度。为此有不同的公式,例如使用sqrt,log10等。
这就是我所做的:
这是代码:
import UIKit
class ViewController: UIViewController {
lazy private var box : UIView = {
let view = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height-300, width: UIScreen.main.bounds.width, height: 300))
view.backgroundColor = .red
return view
}()
private var panGesture : UIPanGestureRecognizer!
private var boxOriginY : CGFloat = 300.0
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(box)
panGesture = UIPanGestureRecognizer(target: self, action: #selector(pullUp(with:)))
box.addGestureRecognizer(panGesture)
}
@objc private func pullUp(with pan: UIPanGestureRecognizer) {
let yTranslation = pan.translation(in: self.view).y
if pan.state == .changed {
let distance = CGFloat(sqrt( Double(-yTranslation) ) * 10) // times 10 to make it smoother
let newHeight : CGFloat = boxOriginY + distance
box.frame = CGRect(x: 0,
y: UIScreen.main.bounds.height-(newHeight),
width: UIScreen.main.bounds.width,
height: newHeight)
}
if pan.state == .ended {
if pan.state == UIPanGestureRecognizer.State.ended {
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
self.box.frame = CGRect(x: 0, y: UIScreen.main.bounds.height-300, width: UIScreen.main.bounds.width, height: 300)
})
}
}
}
}