2011-07-05 28 views
2

我一直在使用在http://www.dev-smart.com/archives/34提供的Horizo​​ntalListView樣本。然而,我的列表項有多個項目,其中包括一個圖像和一個按鈕。當我點擊列表項時,我可以觸發onItemClicked onItemClicked & onItemSelected偵聽器,但是我想將觸摸事件傳播到列表視圖中的按鈕,這可能嗎?單擊Android中的Horizo​​ntalListView內的項目

我的XML文件是

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@+id/item" 
android:orientation="vertical" 
android:layout_width="160dip" 
android:layout_height="160dip" 
android:padding="5dip" 
> 

<ImageView 
android:id="@+id/image" 
android:layout_width="100dip" 
android:layout_height="100dip" 
android:scaleType="centerCrop" 
android:src="@drawable/icon" 
/> 

    <Button android:id="@+id/click" 
android:text="Add" 
android:layout_width="55dip" 
android:layout_height="40dip" 
android:layout_alignRight="@id/image" 
android:layout_alignBottom="@id/image" 
android:layout_above="@id/image" 
android:textSize="14dip" 
android:clickable="true" 
android:textColor="#FFFFFF" 
android:focusable="false" 

/> 

我Horizo​​ntalListView.java如下

import java.util.LinkedList; 
import java.util.Queue; 

import android.content.Context; 
import android.database.DataSetObserver; 
import android.graphics.Color; 
import android.graphics.Rect; 
import android.util.AttributeSet; 
import android.view.GestureDetector; 
import android.view.GestureDetector.OnGestureListener; 
import android.view.MotionEvent; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.Button; 
import android.widget.ListAdapter; 
import android.widget.Scroller; 

public class HorizontalListView extends AdapterView<ListAdapter> { 

    public boolean mAlwaysOverrideTouch = true; 
    protected ListAdapter mAdapter; 
    private int mLeftViewIndex = -1; 
    private int mRightViewIndex = 0; 
    protected int mCurrentX; 
    protected int mNextX; 
    private int mMaxX = Integer.MAX_VALUE; 
    private int mDisplayOffset = 0; 
    protected Scroller mScroller; 
    private GestureDetector mGesture; 
    private Queue<View> mRemovedViewQueue = new LinkedList<View>(); 
    private OnItemSelectedListener mOnItemSelected; 
    private OnItemClickListener mOnItemClicked; 
    private boolean mDataChanged = false; 
    protected Button touchedButton = null; 

    public HorizontalListView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     initView(); 
    } 

    public HorizontalListView(Context context) { 
     super(context); 
     initView(); 
    } 

    private synchronized void initView() { 
     mLeftViewIndex = -1; 
     mRightViewIndex = 0; 
     mDisplayOffset = 0; 
     mCurrentX = 0; 
     mNextX = 0; 
     mMaxX = Integer.MAX_VALUE; 
     mScroller = new Scroller(getContext()); 
     mGesture = new GestureDetector(getContext(), mOnGesture); 
    } 

    @Override 
    public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) { 
     mOnItemSelected = listener; 

    } 

    @Override 
    public void setOnItemClickListener(AdapterView.OnItemClickListener listener){ 
     mOnItemClicked = listener; 

    } 


    private DataSetObserver mDataObserver = new DataSetObserver() { 

     @Override 
     public void onChanged() { 
      synchronized(HorizontalListView.this){ 
       mDataChanged = true; 
      } 
      invalidate(); 
      requestLayout(); 
     } 

     @Override 
     public void onInvalidated() { 
      reset(); 
      invalidate(); 
      requestLayout(); 
     } 

    }; 

    @Override 
    public ListAdapter getAdapter() { 
     return mAdapter; 
    } 

    @Override 
    public View getSelectedView() { 
     //TODO: implement 
     return null; 
    } 

    @Override 
    public void setAdapter(ListAdapter adapter) { 
     if(mAdapter != null) { 
      mAdapter.unregisterDataSetObserver(mDataObserver); 
     } 
     mAdapter = adapter; 
     mAdapter.registerDataSetObserver(mDataObserver); 
     reset(); 
    } 

    private synchronized void reset(){ 
     initView(); 
     removeAllViewsInLayout(); 
     requestLayout(); 
    } 

    @Override 
    public void setSelection(int position) { 
     //TODO: implement 
    } 

    private void addAndMeasureChild(final View child, int viewPos) { 
     LayoutParams params = child.getLayoutParams(); 
     if(params == null) { 
      params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); 
     } 

     addViewInLayout(child, viewPos, params, true); 
     child.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), 
       MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); 
    } 

    @Override 
    protected synchronized void onLayout(boolean changed, int left, int top, int right, int bottom) { 
     super.onLayout(changed, left, top, right, bottom); 

     if(mAdapter == null){ 
      return; 
     } 

     if(mDataChanged){ 
      int oldCurrentX = mCurrentX; 
      initView(); 
      removeAllViewsInLayout(); 
      mNextX = oldCurrentX; 
      mDataChanged = false; 
     } 

     if(mScroller.computeScrollOffset()){ 
      int scrollx = mScroller.getCurrX(); 
      mNextX = scrollx; 
     } 

     if(mNextX < 0){ 
      mNextX = 0; 
      mScroller.forceFinished(true); 
     } 
     if(mNextX > mMaxX) { 
      mNextX = mMaxX; 
      mScroller.forceFinished(true); 
     } 

     int dx = mCurrentX - mNextX; 

     removeNonVisibleItems(dx); 
     fillList(dx); 
     positionItems(dx); 

     mCurrentX = mNextX; 

     if(!mScroller.isFinished()){ 
      post(new Runnable(){ 
       @Override 
       public void run() { 
        requestLayout(); 
       } 
      }); 

     } 
    } 

    private void fillList(final int dx) { 
     int edge = 0; 
     View child = getChildAt(getChildCount()-1); 
     if(child != null) { 
      edge = child.getRight(); 
     } 
     fillListRight(edge, dx); 

     edge = 0; 
     child = getChildAt(0); 
     if(child != null) { 
      edge = child.getLeft(); 
     } 
     fillListLeft(edge, dx); 


    } 

    private void fillListRight(int rightEdge, final int dx) { 
     while(rightEdge + dx < getWidth() && mRightViewIndex < mAdapter.getCount()) { 

      View child = mAdapter.getView(mRightViewIndex, mRemovedViewQueue.poll(), this); 
      addAndMeasureChild(child, -1); 
      rightEdge += child.getMeasuredWidth(); 

      if(mRightViewIndex == mAdapter.getCount()-1){ 
       mMaxX = mCurrentX + rightEdge - getWidth(); 
      } 
      mRightViewIndex++; 
     } 

    } 

    private void fillListLeft(int leftEdge, final int dx) { 
     while(leftEdge + dx > 0 && mLeftViewIndex >= 0) { 
      View child = mAdapter.getView(mLeftViewIndex, mRemovedViewQueue.poll(), this); 
      addAndMeasureChild(child, 0); 
      leftEdge -= child.getMeasuredWidth(); 
      mLeftViewIndex--; 
      mDisplayOffset -= child.getMeasuredWidth(); 
     } 
    } 

    private void removeNonVisibleItems(final int dx) { 
     View child = getChildAt(0); 
     while(child != null && child.getRight() + dx <= 0) { 
      mDisplayOffset += child.getMeasuredWidth(); 
      mRemovedViewQueue.offer(child); 
      removeViewInLayout(child); 
      mLeftViewIndex++; 
      child = getChildAt(0); 

     } 

     child = getChildAt(getChildCount()-1); 
     while(child != null && child.getLeft() + dx >= getWidth()) { 
      mRemovedViewQueue.offer(child); 
      removeViewInLayout(child); 
      mRightViewIndex--; 
      child = getChildAt(getChildCount()-1); 
     } 
    } 

    private void positionItems(final int dx) { 
     if(getChildCount() > 0){ 
      mDisplayOffset += dx; 
      int left = mDisplayOffset; 
      for(int i=0;i<getChildCount();i++){ 
       View child = getChildAt(i); 
       int childWidth = child.getMeasuredWidth(); 
       child.layout(left, 0, left + childWidth, child.getMeasuredHeight()); 
       left += childWidth; 
      } 
     } 
    } 

    public synchronized void scrollTo(int x) { 
     mScroller.startScroll(mNextX, 0, x - mNextX, 0); 
     requestLayout(); 
    } 

    @Override 
    public boolean dispatchTouchEvent(MotionEvent ev) {  
     boolean handled = mGesture.onTouchEvent(ev); 
     return handled; 
    } 

    protected boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
       float velocityY) { 
     synchronized(HorizontalListView.this){ 
      mScroller.fling(mNextX, 0, (int)-velocityX, 0, 0, mMaxX, 0, 0); 
     } 
     requestLayout(); 

     return true; 
    } 

    protected boolean onDown(MotionEvent e) { 
     mScroller.forceFinished(true); 
     return true; 
    } 


    private OnGestureListener mOnGesture = new GestureDetector.SimpleOnGestureListener() { 



     @Override 
     public boolean onDown(MotionEvent e) { 

      return HorizontalListView.this.onDown(e); 

     } 

     @Override 
     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
       float velocityY) { 
       return HorizontalListView.this.onFling(e1, e2, velocityX, velocityY); 
     } 

     @Override 
     public boolean onScroll(MotionEvent e1, MotionEvent e2, 
       float distanceX, float distanceY) { 

      synchronized(HorizontalListView.this){ 
       mNextX += (int)distanceX; 
      } 
      requestLayout(); 

      return true; 
     } 

     @Override 
     public boolean onSingleTapConfirmed(MotionEvent e) { 
      Rect viewRect = new Rect(); 
      for(int i=0;i<getChildCount();i++){ 
       View child = getChildAt(i); 
       int left = child.getLeft(); 
       int right = child.getRight(); 
       int top = child.getTop(); 
       int bottom = child.getBottom(); 
       viewRect.set(left, top, right, bottom); 

           if(viewRect.contains((int)e.getX(), (int)e.getY())){ 

        if(mOnItemClicked != null){ 
         mOnItemClicked.onItemClick(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i)); 
        } 
        if(mOnItemSelected != null){ 
         mOnItemSelected.onItemSelected(HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i)); 
        } 
        break; 
       } 

      } 
      return true; 
     } 
    }; 



} 

我也試過這裏給出Custom list clicking with checkboxes建議,但至今沒有運氣。真的很感謝,如果有人能夠通過水平滾動這樣的自定義視圖來提供觸摸事件處理方式的一些見解。

+0

試着看看這個:http://androidforbeginners.blogspot.com/2010/03/clicking-buttons-in-listview-row.html和這個http://www.geekmind.net/2009/11 /android-custom-list-item-with-nested.html – jkhouw1

+0

正如鏈接中提到的,我嘗試在我的Adapter的getView方法內添加一個按鈕clickListener,但仍然沒有運氣。我甚至嘗試過bt.setFocusable(true); bt.setClickable(true); – 13hsoj

+0

我已經實施了http://www.dev-smart.com/archives/34。但面對滾動問題,並不順利。特別是當我從右到左來時,它正在向上移動。同時有時在滾動時,列表項被點擊。請在我的代碼看這裏:http://stackoverflow.com/questions/17119991/horizo​​ntal-list-view-scrolling-is-not-smooth-in-android – ARIJIT

回答

6

好很多挖成Horizo​​ntalListView的代碼後,我發現,你可以使用它的觸摸事件&通到底層的視圖通過調用

super.dispatchTouchEvent(ev); 

因此,所有我必須做的就是修改方法dispatchTouchEvent

@Override 
public boolean dispatchTouchEvent(MotionEvent ev) {  
    boolean handled = mGesture.onTouchEvent(ev); 
    return handled; 
} 

@Override 
public boolean dispatchTouchEvent(MotionEvent ev) {  
    boolean handled = mGesture.onTouchEvent(ev); 
    return super.dispatchTouchEvent(ev); 
} 

super.dispatchTouchEvent(ev)調用默認的觸摸處理程序。不知道是否有人會需要這樣的行爲,但是如果有人絆倒,這應該是訣竅。

+0

應該 \t @覆蓋 \t公共布爾dispatchTouchEvent(MotionEvent ev){ \t \t super.dispatchTouchEvent(ev); \t \t boolean handled = mGesture.onTouchEvent(ev); \t \t退貨處理; \t} 上面的代碼塊滾動。 – Mathew1990

+0

不,它不會因爲你的處理程序已經處理它,「boolean handling = mGesture.onTouchEvent(ev);」之前的行 – 13hsoj

相關問題