scrollView 嵌套listView不破坏listView的view循环

忙了一周的性能优化,终于搞完了。今天礼拜六上班暂时手里没事,来聊聊这个礼拜做的事。(第一次写技术博客有点小紧张)

首先就是一个scrollView 嵌套listView (这篇文章也主要讲这个)网上很多的方法都外面一个scrollView 里面添加一个 自动测量高度的listView或者scrollView,但是这样做违背了性能优化的初衷,而且谷歌官方不推荐这种做法。基于项目的需求的奇葩,和开发时间问题,迫不得已杀手锏了一回。(如果有不足或者错误的地方欢迎大家斧正。)

在这里需要注意3个问题

1. scrollView 在拉动中 是否把事件分配给子类(需要根据listView在屏幕的位置来判断);

2. scrollView在拉动中 是否收回事件派发自己处理滚动 (子类是否滚到最顶部或者最底部,我只写了顶部的);

3. 子类的高度问题(listView 或者gridView 的高度,为了让大家先理解这里只做简单的listView全屏);

明白这3个问题一切问题都好解决了(当然这3个问题需要有一定的轻量级开发功底 特别是 滑动事件的了解程度)


注:这里只讲 之类是全屏的情况处理(先理解最简单的)

好吧现在我们就来解决这个3个问题  

第一个问题:

这里暂时不需要了解 scrollView 本身的滑动事件

你只需要明白 当listView 完全滑动到了屏幕窗口内部的时候 处理scrollView拦截的事件分发,

所以来吧,判断子类的滑动位置(有很多方法你可以自己设计)在这里我把listView放在最后一个当scrollView滑到最底部时 事件拦截返回false (交给子类处理)。

上代码:


// 这里判断scrollView 是否到了底部
public boolean isBottom() {
    if (getScrollY() >= (getChildAt(0).getMeasuredHeight() - this.getHeight())) {
      return true;
    }
    return false;
  }

 @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    // TODO Auto-generated method stub
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
      currentX = ev.getX();
      currentY = ev.getY();
      break;
    case MotionEvent.ACTION_UP:
      break;
    case MotionEvent.ACTION_MOVE:
      // 左右滑动时 子类 控制滑动 (为了嵌套viewPager)
      // 到达底部时 子类自行控制事件滑动 且之类自己控制父类的事件分发
      if (Math.abs(currentX - ev.getX()) - Math.abs(currentY - ev.getY()) > 0) {
        currentX = ev.getX();
        currentY = ev.getY();
        return false;
      }
      if (isBottom()) { //处理 子类的 下拉滑动事件  <span style="font-family: Arial, Helvetica, sans-serif;">
//  mMainLayout  ==>  scrollview的LinearLayout
        if (mMainLayout.getChildAt(mMainLayout.getChildCount() - 1) instanceof Pullable) {
          if (((Pullable) mMainLayout.getChildAt(mMainLayout.getChildCount() - 1)).canPullDown()) {
                   
            if (currentY - ev.getY() > 0) {//上下滑动的判断  到达子类顶部并且滑动是 向上的不拦截 交给子类
              currentY = ev.getY();
              currentX = ev.getX();
              return false;
            }
          } else {
            currentY = ev.getY();
            currentX = ev.getX();
            return false;   //这里本该做到达底部的判断我偷懒了
          }
        }
      }
      currentY = ev.getY();
      currentX = ev.getX();
      break;
    default:
      break;
    }
    return super.onInterceptTouchEvent(ev);
  }

以上代码我们看到在isbottom的时候 依然要做判断 ,为什么呢? 因为 子类的事件分发 时机都是在scrollView内部完成的 ,所以要适时的获取子类的 滚动位置,并且根据返回的状态来 分发给子类事件.

第二个问题 :

子类是怎么请求事件分发的.(其实是父类通过这些方法获取 子类的事件需求)

1.一个接口

public interface Pullable {
  /**
   * 判断是否可以下拉,如果不需要下拉功能可以直接return false
   * 
   * @return true如果可以下拉否则返回false
   */
  boolean canPullDown();

  /**
   * 判断是否可以上拉,如果不需要上拉功能可以直接return false
   * 
   * @return true如果可以上拉否则返回false
   */
  boolean canPullUp();
}
2.子类实现

public class MyIndexInnerGridView extends GridViewWithHeaderAndFooter implements Pullable{

/**
   * 判断是否可以上拉
   * 
   * @return
   */
  public boolean canPullUp() {
    if (getCount() == 0) {
      // 没有item的时候也可以上拉加载
      return true;
    } else if (getLastVisiblePosition() == (getCount() - 1)) {
      // 滑到底部了
      if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null
          && getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()).getBottom() < = getMeasuredHeight())
        return true;
    }
    return false;
  }

  /**
   * 判断是否可以下拉
   * 
   * @return
   */
  public boolean canPullDown() {
    if (getCount() == 0) {
      // 没有item的时候也可以下拉刷新
      return true;
    } else if (getFirstVisiblePosition() == 0 && getChildAt(0).getTop() >= 0) {
      // 滑到ListView的顶部了
      return true;
    } else
      return false;
  }

其实到这里 代码已经很 明析了. 最后一步就只是设置listView的 高度问题了. 这个代码也挺简单.

第三个问题

在activity里面获取导数据后 延时设置listView的 高度.

  mSvContain.post(new Runnable() {
      @Override
      public void run() {
        // TODO Auto-generated method stub
        LayoutParams layoutParams = mGvMores.getLayoutParams();
        layoutParams.width = LayoutParams.MATCH_PARENT;
        layoutParams.height = mSvContain.getHeight();
        mGvMores.setLayoutParams(layoutParams);
     
        gvAdapter = new GridViewAdapter();
       //这里是一个 加载跟多的 foot (有时间了再讲 这个下拉 和加载更多的 分析 网上的都多少有缺陷性能也不好)
        mGvFooter = (LinearLayout) LinearLayout.inflate(getActivity(), R.layout.listview_footer, null)<span style="white-space:pre">	</span>mGvMores.addFooterView(mGvFooter);
        mGvMores.setAdapter(gvAdapter);
      }
    });

好吧简单的 就介绍到这里, 其实理解了这个最简单的原理 很多复杂的嵌套都可以自己完成了




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值