AndroidのListView之滑動列表項(點擊事件和滑動事件共存)


這里正好在項目有這么一個bt的需求,如下圖ListView的item可以響應點擊事件也可以響應item的左右滑動事件,兩個事件可以相互獨立互不影響。

聽說iphone的list選項就有這樣bt的功能,安卓版的手機QQ和微信和QQ通訊錄也有類似的效果,在網上各種尋早方案都試過,要不只能滑動不能點擊要么就只能點擊不能滑動,而且操作很不靈敏,網上的代碼都是在itemView的onTouch方法里處理,判斷down和up的像素差。其實這樣操作相當不便,down-up這樣的其實只能算拖動事件而不是滑動事件,所以你會聯想到scroll和fling的區別。

大家可以看看我之前的做法,使用ontouch方法處理的,很難獨立滑動事件跟點擊事件,就算可以滑動也是很靈敏,操作10次難得一次成功。

class SwipeListener implements View.OnTouchListener{
        
        ViewHolder holder;
        HouseList_Item item;
        int startX = 0;
        int endX = 0;
        
        public SwipeListener(ViewHolder holder, HouseList_Item item) {
            super();
            this.holder = holder;
            this.item = item;
        }



        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            
            if(event.getAction() == MotionEvent.ACTION_DOWN){
                startX = (int)event.getX();
                Debuger.log_e("startX", ""+startX);
                return true;
            }else if(event.getAction() == MotionEvent.ACTION_UP){
                endX = (int)event.getX();
                Debuger.log_e("endX", ""+endX);
                if(startX - endX > 120){
                    Debuger.log_e("觸發", "左划");
                    holder.llMenu.setVisibility(View.VISIBLE);
                    return false;
                }else if(endX - startX >120){
                    Debuger.log_e("觸發", "右划");
                    holder.llMenu.setVisibility(View.GONE);
                    return true;
                }else{
                    Toast.makeText(ctx, "點擊item", 3000).show();
                    return true;
                }
               

            }
            return true;
        }
        
    }

代碼有注釋相信大家都看得懂,像上面這樣子也差不多讓滑動事件和點擊事件獨立出來了。一開始還傻乎乎的用ListView的OnItemClick事件,搭配這樣功能真的是碉堡。

 

經過半天的努力探索,今天終於很流暢得實現這效果。下面是新的代碼:

這個是適配器的代碼,有部分省略,主要是GestureDetector 這樣一個手勢監聽器。

public class HouseList_Adapter extends BaseAdapter{

    private GestureDetector detector;
    private List<HouseList_Item> list ;
    private Context ctx = null;
    private LayoutInflater inflater = null;
    FlingListeber listener;

    public HouseList_Adapter( Context ctx,List<HouseList_Item> list) {
        super();
        this.list = list;
        this.ctx = ctx;
        inflater = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        listener = new FlingListeber();
        detector = new GestureDetector(listener);
    }

    @Override
    public View getView(int arg0, View arg1, ViewGroup arg2) {
        // TODO Auto-generated method stub
        ViewHolder holder = null;
        if(arg1==null){
            arg1 = inflater.inflate(R.layout.house_item_layout, null);
            holder = new ViewHolder();
            holder.llItem = (LinearLayout)arg1.findViewById(R.id.llItem);
            holder.tvTitle = (TextView)arg1.findViewById(R.id.tvTitle);
            holder.tvBuildeArea = (TextView)arg1.findViewById(R.id.tvArea);
            holder.tvPrice = (TextView)arg1.findViewById(R.id.tvPrice);
            holder.tvPriceUnit = (TextView)arg1.findViewById(R.id.tvPriceUnit);
            holder.tvRoom = (TextView)arg1.findViewById(R.id.tvRoom);
            holder.llFlag = (LinearLayout)arg1.findViewById(R.id.llFlag);
            holder.ivFlag1 = (ImageView)arg1.findViewById(R.id.ivFlag1);
            holder.ivFlag2 = (ImageView)arg1.findViewById(R.id.ivFlag2);
            holder.ivFlag3 = (ImageView)arg1.findViewById(R.id.ivFlag3);
            holder.ivFlag4 = (ImageView)arg1.findViewById(R.id.ivFlag4);
            holder.llMenu = (LinearLayout)arg1.findViewById(R.id.house_ltem_menu);
            holder.ivCall = (Button)arg1.findViewById(R.id.ivCall);
            holder.ivDetails = (Button)arg1.findViewById(R.id.ivCall);
            holder.ivMap = (Button)arg1.findViewById(R.id.ivMap);
            holder.ivSend = (Button)arg1.findViewById(R.id.ivSend);
            arg1.setTag(holder);
            
        }else{
            holder = (ViewHolder)arg1.getTag();
        }
        final HouseList_Item item = list.get(arg0);
        listener.setItem(item);
        //holder.llItem.setOnTouchListener(new SwipeListener(holder,item));
        holder.llItem.setOnTouchListener(new View.OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                return detector.onTouchEvent(event);
            }
        });
    
     }
class FlingListeber implements GestureDetector.OnGestureListener{ HouseList_Item item; ViewHolder holder; public HouseList_Item getItem() { return item; } public void setItem(HouseList_Item item) { this.item = item; } public ViewHolder getHolder() { return holder; } public void setHolder(ViewHolder holder) { this.holder = holder; } @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub if(e2.getX()-e1.getX()>20){ Toast.makeText(ctx, "左滑"+item.areaName, 3000).show(); }else if(e1.getX()-e2.getX()>20){ Toast.makeText(ctx, "右滑"+item.areaName, 3000).show(); } return false; } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // TODO Auto-generated method stub return false; } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub Toast.makeText(ctx, "點擊item", 3000).show(); return false; } } }

這樣讓item的滑動事件交給onFling去處理,點擊事件交給onSingleTapUp這樣就可以讓兩個事件相互獨立了,但是這樣執行發現還是會有很不順暢滑動的時候,后來我一想那肯定是listview的上下滑動跟item的左右滑動事件有沖突,所以就把之前定義的一個ScrollView里處理touch事件拷過去就很靈敏了,百發百中。

// 滑動距離及坐標  
    private float xDistance, yDistance, xLast, yLast;
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
         switch (ev.getAction()) {  
         case MotionEvent.ACTION_DOWN:  
             xDistance = yDistance = 0f;  
             xLast = ev.getX();  
             yLast = ev.getY();  
             break;  
         case MotionEvent.ACTION_MOVE:  
             final float curX = ev.getX();  
             final float curY = ev.getY();  
               
             xDistance += Math.abs(curX - xLast);  
             yDistance += Math.abs(curY - yLast);  
             xLast = curX;  
             yLast = curY;  
               
             if(xDistance > yDistance){  
                 return false;  
             }    
     }  

        return super.onInterceptTouchEvent(ev);
    }

把這段代碼復制到一個ListView的擴展類里覆蓋就行。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM