忙了一周的性能优化,终于搞完了。今天礼拜六上班暂时手里没事,来聊聊这个礼拜做的事。(第一次写技术博客有点小紧张)
首先就是一个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);
}
});
好吧简单的 就介绍到这里, 其实理解了这个最简单的原理 很多复杂的嵌套都可以自己完成了