前几天写的复杂ListView的实现方式。
使用的场景:
在列表的item中存在例如workspace的view
package com.hyena.school.view; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.AbsListView; import android.widget.ListView; import android.widget.AbsListView.OnScrollListener; import com.hyena.framework.log.HyenaLog; /** * 列表 * @author yangzc * */ public class HyenaListView extends ListView implements OnScrollListener { private View mHidenHeaderView; private List<View> mStaticHeaderViews;//静态头,不响应触摸事件 public HyenaListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initListView(); } public HyenaListView(Context context, AttributeSet attrs) { super(context, attrs); initListView(); } public HyenaListView(Context context) { super(context); initListView(); } private void initListView() { mStaticHeaderViews = new ArrayList<View>(); this.setOnScrollListener(this); } /** * 隐藏的HeaderView * 这个View始终处于隐藏状态 * @param view */ public void setHidenHeaderView(View view){ mHidenHeaderView = view; this.addHeaderView(view); } /** * 静态的HeaderView * 这个View将不响应OnTouchEvent事件 * @param view */ public void addStaticHeaderView(View view){ mStaticHeaderViews.add(view); this.addHeaderView(view); } private int MAX_X_DISTANCE = 30; private int mDirection = NO_DIRECTION;//方向 private final static int NO_DIRECTION = 0; private final static int HORIZONAL = 1; private final static int VERTICAL = 2; private int mLastMotionX; private int mLastMotionY; /** * 处理静态View的手势识别 */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { HyenaLog.v("yangzc", "dispatchTouchEvent"); int x = (int) ev.getX(); int y = (int) ev.getY(); View touchView = getTouchingStaticHeader(x, y); if(touchView == null) return super.dispatchTouchEvent(ev); int action = ev.getAction(); switch(action){ case MotionEvent.ACTION_DOWN: mDirection = NO_DIRECTION; mLastMotionX = x; mLastMotionY = y; touchView.dispatchTouchEvent(ev); super.dispatchTouchEvent(ev); case MotionEvent.ACTION_MOVE: if(mDirection == VERTICAL) return super.dispatchTouchEvent(ev); if(mDirection == HORIZONAL){ touchView.dispatchTouchEvent(ev); return true; } if(Math.abs(mLastMotionX - x) > MAX_X_DISTANCE){ mDirection = HORIZONAL; }else if(Math.abs(mLastMotionY - y) > MAX_X_DISTANCE){ mDirection = VERTICAL; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mDirection = NO_DIRECTION; touchView.dispatchTouchEvent(ev); super.dispatchTouchEvent(ev); break; } return true; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { HyenaLog.v("yangzc", "onInterceptTouchEvent"); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { HyenaLog.v("yangzc", "onTouchEvent"); if(mHidenHeaderView == null){ return super.onTouchEvent(ev); } int firstVisablePos = getFirstVisiblePosition(); View firstView = this.getChildAt(firstVisablePos); int bottom = firstView.getBottom(); int action = ev.getAction(); switch(action){ case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: if(firstVisablePos == 0 && bottom > 0){ int left = firstView.getLeft(); int right = firstView.getRight(); int height = firstView.getHeight(); firstView.layout(left, -height, right, 0); requestLayout(); } break; case MotionEvent.ACTION_CANCEL: break; } return super.onTouchEvent(ev); } /** * 当关联到Windows时执行 */ @Override protected void onAttachedToWindow() { if(mHidenHeaderView != null){ setSelection(1); } super.onAttachedToWindow(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); //当点击返回键,然后重新拉起应用时定位到以一个合法的可见View scrollToFirstVisibleView(); } /** * 取得当前触摸到的静态View * @param x X坐标 * @param y Y坐标 * @return */ private View getTouchingStaticHeader(int x, int y){ int position = pointToPosition(x, y); if(mStaticHeaderViews.contains(this.getChildAt(position))){ return this.getChildAt(position); } return null; } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } /** * 滚动状态改变 */ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { switch(scrollState){ case OnScrollListener.SCROLL_STATE_IDLE://空闲 case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://滚动中 case OnScrollListener.SCROLL_STATE_FLING://滑动中 scrollToFirstVisibleView(); break; } } /** * 滚动到第一个可见View * * 如果当前List第一个可见区域为隐藏区域则定位到一个个可见区域 */ private void scrollToFirstVisibleView(){ int firstVisablePos = getFirstVisiblePosition(); View firstView = this.getChildAt(firstVisablePos); if(firstView == null)return; int bottom = firstView.getBottom(); if(firstVisablePos == 0 && bottom > 0){ setFastScrollEnabled(false); int left = firstView.getLeft(); int right = firstView.getRight(); int height = firstView.getHeight(); firstView.layout(left, -height, right, 0); requestLayout(); } } // private void cancelFling(){ // try { // Field field = AbsListView.class.getDeclaredField("mFlingRunnable"); // Object obj = field.get(null); // Method method = obj.getClass().getDeclaredMethod("endFling", new Class[0]); // method.invoke(obj); // } catch (SecurityException e) { // e.printStackTrace(); // } catch (NoSuchFieldException e) { // e.printStackTrace(); // } catch (IllegalArgumentException e) { // e.printStackTrace(); // } catch (IllegalAccessException e) { // e.printStackTrace(); // } catch (NoSuchMethodException e) { // e.printStackTrace(); // } catch (InvocationTargetException e) { // e.printStackTrace(); // } // } }