全部tableView会出现一个我们不想见见的反弹效果,停止响应滚动

进而大家在 pan 的手势的 recognizer
中一呼百应处理那种滑动经过临界区域的情景:

     
scrollView在滑倒最边上(左或右)的时候,为了唤起用户已经滑到最边上了(左或右),再持续向左(右)滚动的话会有一个反弹的效力,那就造成左滑删除的时候,整个tableView会出现一个大家不想看看的反弹效果。

虽说苹果指出大家决不嵌套 UIScrollview
,然而那话到底是对开发者说的,架不住设计师就是要那样画设计图。
我遇见的光景类似那样,顶部有一个事先显示的封皮,当封面滚出屏幕后上边内容的
ScrollView
开始滚动。因为介绍、目录、评价多少个tab是足以左右轮转的,所以具体内容是嵌套在一个
ScrollView 里的。

问题1:

‘UIScrollView’s built-in pan gesture recognizer must have its scroll
view as its delegate.’

第一,新建一个MyScrollView类,让其继续于UIScrollView,并且坚守UIGestureRecognizerDelegate协议。

在代理方法<code> scrollViewDidScroll
</code>中展开判断,当mainScrollView 划出 150
后,为止响应滚动,那时手指再滑动,自然就是显得内容的 subScrollView
响应了。

问题2:

据此那种简易的粗鲁的方案不可以化解问题。毕竟用户是我们五伯。

还有commitEditingStyle等等的函数,那里就不一一例举了。那里附上自己的gitHub地址:github.com/juncheng785245941

首先步就是通过设置 ScrollView 的 isScrollEnabled 属性来支配哪个响应。

      谢谢各位。

  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
    }

那种方案的欠缺就是透过临界点的移位曲线会不自然。原生的滑行有个仿物理的弹性,而大家是直接设置
contentOffset 获得的,是线性的。

self.scrollView.bounces = NO;

跟着我们定义八个 bool 值判断当前滚动的 ScrollView

#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;

  }

}

    @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.这几个函数里面的情趣是即使一个手势没有被辨认的话,那么就让多少个gestureRecognizer可以被识别,也就是本文的scrollView与tableView的cell的滑行手势可以而且被识别。

只是那几个不难的方案在实际操作中有一个很大的流弊。用户并不总是无微不至的在滑行了
150 pt后,停出手。然后再起来开展下四次的滑行。如若用户五回性滚了 160
,mainScrollView 就会在滚动到 150 后停止响应,此时因为是四回击势,
subScrollView
也不会响应。用户就会有被中止的感到,要求第二次滑动才能继续滚动。

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer
*)otherGestureRecognizer {

     if(gestureRecognizer.state != 0) {

     return YES;

}else {

     return NO;

}

世家都了然种种 ScrollView 都带了一个 panGestureRecognizer
。此时,大家开端幻想,倘若可以自己主宰这几个 pan 手势就好了。
于是我们写下了那行的代码发轫进行尝试:

不留余地办法:

    var mainScrollEnabled = false
    var subScrollEnabled = false

明天就写到那里了,第三回用简书,语言不当或者有不当的地点请多多指教,将来还会时不时写一些谈得来在iOS开发仍然说是学习的时候碰到的题材与解决办法。我的目的是能让拥有程序猿更少的纠结于意外的bug,更少的熬夜,更自在的编程。

补充

iOS
嵌套UIScrollview的滑动争论另一种缓解方案
的小说中补充了用
DynamicKit 模仿 ScrollView 的惯性。纵然错综复杂了一些不过真正效果好多了。

迎接关切本身的新浪:@没故事的卓同学

接下来重写下类方法:

自身来翻译一下:

首先在tableView里面完成cell的左滑删除作用是挺不难的,相信大家都清楚如何是好。但是,当有五个tableView放在一个scrollView里面的时候,会发出一多样的题材。

如此那般设置之后就足以在不影响滚动的状态下得到 pan 手势的参数。

     
当您把scrollView滑到最边上(左或右)的时候,当你继续做滑想要让cell接收左滑手势的时候,那时滑动删除的风浪被尾部的UIScrollview给响应了,cell根本拿不到这么些滑入手势。tableView是UIScrollview
的子类,cell里面的ContentView好像在iOS7.0自此也是UIScrollview
,再加底部一个UIScrollview,那滑出手势事件该怎么传递好呢,给何人都很是啊。
给了尾部,那么就无奈滑动删除,给了cell那么正常的左右滑行又很是了。

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)
                }
            }
        }
    }

缓解格局:

在 scrollViewDidScroll 中设置:

@interface MyScrollview : UIScrollView
<UIGestureRecognizerDelegate>

竭泽而渔的思绪是我们协调丰硕一个联动的 pan
手势。注目的在于<code>UIGestureRecognizerDelegate</code>中的<code>shouldRecognizeSimultaneously</code>重临true。

要害代码:

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
            }
        }
    }

上面给出已毕滑动删除常用到的方法。

不过事实上边临的问题都是一般的,嵌套了 ScrollView
后,须要一个标准来支配某个具体时刻哪个 ScrollView 响应滑动事件。

不过那样未来,又会并发一个新的题目,也就是当scrollView在左右滑动的时候,tableView也能而且的左右滑动。造成那种光景的原故是地点MyScrollView里面重写的函数造成了五个手势同时被响应。解决那种问题的主意是在ViewController类里面处理滚动时候的事件。

        mainScrollView.panGestureRecognizer.delegate = self

好了,到此结束,为嵌套在scrollView里面的tableView达成滑动删除的法力所遭受的题材早就缓解了。注意,那里解决的是给右侧的tableView扩张滑动删除,假若你的需如若给左侧的tableView增添滑动删除,那么解决方案是:拿起键盘砸向产品经营。

世家都明白 iOS 的付出体验尤其好,苹果的 API 都专门为大家着想。程序 run
起来后 xcode 就会给你一个 crash:

-(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,并以数组的地势再次回到,使得左滑时候可以产出多个按钮。

代码的意思是当您在滑行scrollView的时候,把具有的tableView设置为不可滑动,而当scrollView滑动截止的时候,再把tableView设置为可以滑动,那样就能幸免scrollView与tableView同时滑动了。

iOS的UIGestureRecognizer基类内涵盖
Tap(点击)、Pinch(捏合)、Rotation(旋转)、Swipe(滑动)、Pan(拖移)、LongPress(长按)那三种常用手势动作,又细分单击、双击、左滑、右滑等操作。

   
会并发那种效应,是因为苹果为了让用户精晓scrollView已经滑到了最边上了,而不是程序卡了仍然出现问题了而不可以滑动。所以,scrollView对象里面有三个属性,分别是bounces,bounceHorizontally与bounceVertically五个特性,通过
self.scrollView.bounces =
NO;那行代码就可以让scrollView滑倒边上的时候不会冒出反弹效果。

相关文章