ScrollView和Fragment中的ListView、WebView滑动冲突问题的解决

        日常开发中很少会碰到ScrollView中嵌套listview或webview的情况,而且谷歌官方也不推荐这么做,但是也不是一定不会有这样的需求,毕竟定需求的不是我们程序员,而是产品经理。比如像下面这种需求:
       可以看到,整个页面有一个共同的头部,下面有两个tab,左边tab下是个可以滚动的webview,右边是个listview。要求listview和webview在默认情况下不滚动,但外部整个页面可以滚动,当外层页面滚动到底部时,也就是两个tab的位置大概位于actionbar下方的时候,要求listview和webview自己能滑动而外层不动,当listview或webview下拉到顶部时,又让外层接管滑动,此时共同的头部可以拉下来。
        碰到这种情况,一般的情况肯定是外层套个scrollview,两个tab里分别放个fragment,左右两个fragment分别放置listview。但是很不幸,这样做之后发现listview根本连显示都显示不了,更别提可以滑动了。读者一试便知。原因就在与scrollview和listview存在滑动事件的冲突,那么如何解决这个问题呢?网上有人给出了一个方法:手动计算listview的高度然后显示地设置他的高度。你只需要在listview.setAdapter()方法后调用如下代码:
   
   
   
  1. public void setListViewHeightBasedOnChildren(ListView listView) {
  2. ListAdapter listAdapter = listView.getAdapter();
  3. if (listAdapter == null) {
  4. return;
  5. }
  6. int totalHeight = 0;
  7. for (int i = 0; i < listAdapter.getCount(); i++) {
  8. View listItem = listAdapter.getView(i, null, listView);
  9. listItem.measure(0, 0);
  10. totalHeight += listItem.getMeasuredHeight();
  11. }
  12. ViewGroup.LayoutParams params = listView.getLayoutParams();
  13. params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
  14. Log.d(TAG, "params.height: "+params.height);
  15. listView.setLayoutParams(params);
  16. }
        很不幸!这段代码只有在没有fragment的情况下才有效果,现在的情况是scrollview在宿主Activity中,而listview却在其中一个fragment中,按理说fragment也是放在Activity中那就相当于listview也在Activity中,但是实际情况就是显示不出来listview,具体什么原因我暂时也不清楚。
        那既然在没有fragment的情况下才可以显示listview,那如果不用fragment怎么达到上述切换的效果呢?很简单!在Activity中切换的位置放置个空的容器FrameLayout,然后在切换tab的时候动态添加进想要的view,无论是webvie还是listview甚至是更复杂的view。其实在fragment出现之前,解耦Activity就采用的是这中方式。
我们采用mvc的思想抽象出一个controller基类,功能类似于一个简单的fragment,里面可以绑定view视图和model数据。
   
   
   
  1. public abstract class BaseController
  2. {
  3. public View mRootView;
  4. public Context mContext;
  5. public BaseController(Context context){
  6. this.mContext = context;
  7. // 在构造中 就加载显示的view
  8. mRootView = initView(context);
  9. }
  10. /**
  11. * 初始化view的方法让子类去实现
  12. * @return
  13. */
  14. protected abstract View initView(Context context);
  15. /**
  16. * 加载数据的方法,子类可以实现,也可以不实现
  17. */
  18. public void initData(){
  19. }
  20. /**
  21. * 暴露出去的获得根view的方法
  22. * @return
  23. */
  24. public View getRootView()
  25. {
  26. return mRootView;
  27. }
  28. }
        然后继承这个基类分别创建LeftController 和 RightController,我们先以RightController为例,来把显示listview显示出来。
   
   
   
  1. public class RightController extends BaseController {
  2. private static final String TAG = "RightController";
  3. private ListView mListView;
  4. private List<String> mDatas;
  5. public RightController(Context context) {
  6. super(context);
  7. }
  8. @Override
  9. protected View initView(Context context) {
  10. // TextView readView = new TextView(context);
  11. // readView.setText("right-页面");
  12. View rootView = View.inflate(context, R.layout.controller_right, null);
  13. mListView = (ListView) rootView.findViewById(R.id.lv);
  14. prepareData();
  15. RightAdapter rightAdapter = new RightAdapter(context, mDatas);
  16. mListView.setAdapter(rightAdapter);
  17. setListViewHeightBasedOnChildren(mListView);
  18. return rootView;
  19. }
  20. private void prepareData() {
  21. mDatas = new ArrayList<>();
  22. for (int i = 0; i < 20; i++) {
  23. mDatas.add("item_" + i);
  24. }
  25. }
  26. /**
  27. * 在scrollview中完整显示listview
  28. *
  29. * @param listView
  30. */
  31. public void setListViewHeightBasedOnChildren(ListView listView) {
  32. ListAdapter listAdapter = listView.getAdapter();
  33. if (listAdapter == null) {
  34. return;
  35. }
  36. int totalHeight = 0;
  37. // for (int i = 0; i < listAdapter.getCount(); i++) {
  38. for (int i = 0; i < 10; i++) {
  39. View listItem = listAdapter.getView(i, null, listView);
  40. listItem.measure(0, 0);
  41. totalHeight += listItem.getMeasuredHeight();
  42. }
  43. ViewGroup.LayoutParams params = listView.getLayoutParams();
  44. params.height = totalHeight + (listView.getDividerHeight() * 5);// (listAdapter.getCount() - 1));
  45. Log.d(TAG, "params.height: "+params.height);
  46. listView.setLayoutParams(params);
  47. }
  48. }
        而在Activity的tab切换事件中只需这样两句代码即可把controller的view动态添加进Activity中:
   
   
   
  1. @Override
  2. public
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 iOS 开发,嵌套在 `UIScrollView` 的 `UITableView` 在滑动时可能会与 `UIScrollView` 的滑动手势产生冲突,导致无法正常滑动。这个问题可以通过以下两种方式解决: 1. 禁用 `UIScrollView` 的滑动手势 可以通过设置 `UIScrollView` 的 `panGestureRecognizer` 的 `enabled` 属性为 `NO` 来禁用滑动手势,这样就不会与 `UITableView` 的滑动手势产生冲突了。 ```objc scrollView.panGestureRecognizer.enabled = NO; ``` 2. 实现 `UIGestureRecognizerDelegate` 协议的方法 在 `UIViewController` 实现 `UIGestureRecognizerDelegate` 协议的 `gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:` 方法,可以控制两个手势是否允许同时识别。在这个方法,可以判断当前的手势是否为 `UIScrollView` 的滑动手势,如果是,则允许与 `UITableView` 的滑动手势同时识别,否则不允许。 ```objc - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { if ([gestureRecognizer.view isKindOfClass:[UIScrollView class]] && [otherGestureRecognizer.view isKindOfClass:[UITableView class]]) { return YES; } return NO; } ``` 需要注意的是,在实现这个方法时,要将 `UIScrollView` 的 `delegate` 设置为当前的 `UIViewController`,否则这个方法不会被调用。 ```objc scrollView.delegate = self; ``` 以上两种方式都可以解决嵌套在 `UIScrollView` 的 `UITableView` 滑动手势冲突问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值