前几天写的复杂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();
// }
// }
}