即便苹果提议我们不要嵌套 UIScrollview
,可是那话到底是对开发者说的,架不住设计师就是要那样画设计图。
自家碰到的光景类似那样,顶部有一个先行浮现的书皮,当封面滚出显示屏后上面内容的
ScrollView
开头滚动。因为介绍、目录、评价两个tab是可以左右轮转的,所以具体内容是嵌套在一个
ScrollView 里的。
首先在tableView里面完成cell的左滑删除功效是挺简单的,相信我们都晓得如何是好。不过,当有多少个tableView放在一个scrollView里面的时候,会暴发一多级的难点。
而是其实面临的题材都以相似的,嵌套了 ScrollView
后,须要一个准绳来控制某个具体时刻哪个 ScrollView 响应滑动事件。
率先步就是透过安装 ScrollView 的 isScrollEnabled 属性来支配哪个响应。
问题1:
@IBOutlet weak var mainScrollView: UIScrollView!
@IBOutlet weak var subScrollView: UIScrollView!
let maxOffsetY: CGFloat = 150
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == mainScrollView {
if scrollView.contentOffset.y >= maxOffsetY {
mainScrollView.isScrollEnabled = false
subScrollView.isScrollEnabled = true
}
}else {
// 当 subScrollView 滑动到顶时,停止响应,mainScrollView 开始响应。
if scrollView.contentOffset.y <= 0 {
subScrollView.isScrollEnabled = false
mainScrollView.isScrollEnabled = true
}
}
}
scrollView在滑倒最边上(左或右)的时候,为了唤起用户已经滑到最边上了(左或右),再持续向左(右)滚动的话会有一个反弹的功力,那就招致左滑删除的时候,整个tableView会出现一个我们不想见到的反弹效果。
在代理方法<code> scrollViewDidScroll
</code>中展开判断,当mainScrollView 划出 150
后,为止响应滚动,那时手指再滑动,自然就是显得内容的 subScrollView
响应了。
斩草除根办法:
不过这些大约的方案在实际操作中有一个很大的害处。用户并不三番五次完美的在滑行了
150 pt后,停出手。然后再先河进行下五遍的滑动。若是用户几回性滚了 160
,mainScrollView 就会在滚动到 150 后停下响应,此时因为是三遍击势,
subScrollView
也不会响应。用户就会有被搁浅的感觉,须要第二次滑动才能三番三次滚动。
会产出这种效益,是因为苹果为了让用户明白scrollView已经滑到了最边上了,而不是程序卡了照旧出现难点了而不大概滑动。所以,scrollView对象里面有多个属性,分别是bounces,bounceHorizontally与bounceVertically四特性格,通过
self.scrollView.bounces =
NO;那行代码就足以让scrollView滑倒边上的时候不会并发反弹效果。
于是那种不难的野蛮的方案不可以解决难点。毕竟用户是大家大叔。
重在代码:
大家都知晓各种 ScrollView 都带了一个 panGestureRecognizer
。此时,我们初步幻想,借使可以自身决定那几个 pan 手势就好了。
于是大家写下了那行的代码发轫举行尝试:
self.scrollView.bounces = NO;
mainScrollView.panGestureRecognizer.delegate = self
问题2:
世家都精晓 iOS 的支付体验尤其好,苹果的 API 都专门为大家着想。程序 run
起来后 xcode 就会给您一个 crash:
当您把scrollView滑到最边缘(左或右)的时候,当您继承做滑想要让cell接收左滑手势的时候,那时滑动删除的轩然大波被底部的UIScrollview给响应了,cell根本拿不到这几个滑下手势。tableView是UIScrollview
的子类,cell里面的ContentView好像在iOS7.0自此也是UIScrollview
,再加尾部一个UIScrollview,那滑出手势事件该怎么传递好呢,给谁都十分啊。
给了尾部,那么就无可怎样滑动删除,给了cell那么正常的左右滑动又不行了。
‘UIScrollView’s built-in pan gesture recognizer must have its scroll
view as its delegate.’
化解方法:
自小编来翻译一下:
首先,新建一个MyScrollView类,让其持续于UIScrollView,并且遵守UIGestureRecognizerDelegate协议。
缓解的笔触是我们友好丰富一个联动的 pan
手势。注意在<code>UIGestureRecognizerDelegate</code>中的<code>shouldRecognizeSimultaneously</code>再次回到true。
@interface MyScrollview : UIScrollView
<UIGestureRecognizerDelegate>
let pan = UIPanGestureRecognizer(target: self, action: #selector(ViewController.panGestureRecognizerAction(recognizer:)))
pan.delegate = self
mainScrollView.addGestureRecognizer(pan)
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
iOS的UIGestureRecognizer基类内含有
Tap(点击)、Pinch(捏合)、Rotation(旋转)、Swipe(滑动)、Pan(拖移)、LongPress(长按)那两种常用手势动作,又分开单击、双击、左滑、右滑等操作。
如此那般设置之后就能够在不影响滚动的气象下得到 pan 手势的参数。
接下来重写下类方法:
随后我们定义八个 bool 值判断当前滚动的 ScrollView
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {if(gestureRecognizer.state != 0) {
return YES;
}else {
return NO;
}
var mainScrollEnabled = false
var subScrollEnabled = false
重写之后让这几个类绑定你界面中的scrollView.这么些函数里面的意趣是只要一个手势没有被辨认的话,那么就让七个gestureRecognizer可以被识别,约等于本文的scrollView与tableView的cell的滑行手势可以而且被识别。
在 scrollViewDidScroll 中设置:
只是如此之后,又会现出一个新的题材,也等于当scrollView在左右滑动的时候,tableView也能同时的左右滑动。造成那种情景的原委是上面MyScrollView里面重写的函数造成了几个手势同时被响应。化解那种题材的法门是在ViewController类里面处理滚动时候的轩然大波。
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == mainScrollView {
if scrollView.contentOffset.y >= maxOffsetY {
scrollView.setContentOffset(CGPoint(x: 0, y: maxOffsetY), animated: false)
mainScrollView.isScrollEnabled = false
subScrollView.isScrollEnabled = true
subScrollEnabled = true
mainScrollEnabled = false
}
}else {
if scrollView.contentOffset.y <= 0 {
scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
subScrollView.isScrollEnabled = false
mainScrollView.isScrollEnabled = true
mainScrollEnabled = true
subScrollEnabled = false
}
}
}
#pragma mark – ScrollView delegate
– (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if(scrollView == self.myScrollView) {
self.tableView1.scrollEnabled = NO;
self.tableView2.scrollEnabled = NO;
}
}
– (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if(scrollView == self.myScrollView) {
self.tableView1.scrollEnabled = YES;
self.tableView2.scrollEnabled = YES;
}
}
继而大家在 pan 的手势的 recognizer
中一呼百应处理那种滑动经过临界区域的景观:
代码的情趣是当你在滑行scrollView的时候,把具有的tableView设置为不可滑动,而当scrollView滑动甘休的时候,再把tableView设置为可以滑动,那样就能幸免scrollView与tableView同时滑动了。
var currentPanY: CGFloat = 0
func panGestureRecognizerAction(recognizer: UIPanGestureRecognizer) {
if recognizer.state != .changed{
currentPanY = 0
// 每次滑动结束都清空状态
mainScrollEnabled = false
subScrollEnabled = false
}else {
let currentY = recognizer.translation(in: mainScrollView).y
// 说明在这次滑动过程中经过了临界点
if mainScrollEnabled || subScrollEnabled {
if currentPanY == 0 {
currentPanY = currentY //记录下经过临界点是的 y
}
let offsetY = currentPanY - currentY //计算在临界点后的 offsetY
if mainScrollEnabled {
let supposeY = maxOffsetY + offsetY
if supposeY >= 0 {
mainScrollView.contentOffset = CGPoint(x: 0, y: supposeY)
}else {
mainScrollView.contentOffset = CGPoint.zero
}
}else {
subScrollView.contentOffset = CGPoint(x: 0, y: offsetY)
}
}
}
}
好了,到此截至,为嵌套在scrollView里面的tableView完结滑动删除的功能所遇到的难点一度缓解了。注意,那里消除的是给左边的tableView扩张滑动删除,借使您的必要是给左侧的tableView扩大滑动删除,那么消除方案是:拿起键盘砸向产品CEO。
那种方案的症结就是由此临界点的活动曲线会不自然。原生的滑动有个仿物理的弹性,而小编辈是平昔设置
contentOffset 得到的,是线性的。
上边给出落成滑动删除常用到的法门。
补充
iOS
嵌套UIScrollview的滑行争辩另一种缓解方案的小说中补充了用
DynamicKit 模仿 ScrollView 的惯性。尽管错综复杂了一些不过真正效果好多了。
欢迎关切自身的今日头条:@没轶闻的卓同学
-(NSString *)tableView:(UITableView *)tableView
titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath
*)indexPath {return @”删除”;
}
该办法重回的是您左滑时候出现的文字提醒。
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {return UITableViewCellEditingStyleDelete;
}
该方法是依据indexPath重返tableView里面每一行的编排类型。包含UITableViewCellEditingStyleDelete,UITableViewCellEditingStyleNone与UITableViewCellEditingStyleInsert.
-(NSArray*)tableView:(UITableView *)tableView
editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {UITableViewRowAction* deleteAction = [UITableViewRowAction
rowActionWithStyle:UITableViewRowActionStyleNormal title:@”删除”
handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath *
_Nonnull indexPath) {那其间写点击按钮的所响应的轩然大波。
}];
return @[deleteAction];
}
本条函数可以创立七个action,并以数组的地势重回,使得左滑时候能够出现八个按钮。
再有commitEditingStyle等等的函数,那里就不一一例举了。这里附上自个儿的gitHub地址:github.com/juncheng785245941