zoukankan      html  css  js  c++  java
  • 手把手实现腾讯qq拖拽删去效果(二)

      这节,就一个任务如何把上节自定义的翻页动画控件整进下拉列表中去。

      由于是自定义的下拉列表控件,我们需要自定义能够上啦下滑的listview,这势必会造成这个问题,上拉刷新要响应相应touch事件,拖拽也似乎也要相应触摸事件,这势必会造成了一种事件的冲突了,怎么解决了。我这里用一个变量来区分一下,伪代码如下:

      前面说了,这么多了,我们直接点评代码把:

    package com.routemap_infomation.utils;
    
    import java.util.Date;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.GestureDetector;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewDebug.IntToString;
    import android.view.ViewGroup;
    import android.view.animation.LinearInterpolator;
    import android.view.animation.RotateAnimation;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.HorizontalScrollView;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    import com.routemap_infomation.myfocus.R;
    import com.routemap_infomation.myfocus.LineFocusActivity.RouteItem;
    import com.routemap_infomation.utils.GestureJudgeUtils.OnGestureResult;
    
    /**
     * 该类主要是完成 头部部分的功能封装
     * 
     * 一个可以监听ListView是否滚动到最顶部或最底部的自定义控件
     * 只能监听由触摸产生的,如果是ListView本身Flying导致的,则不能监听</br> 如果加以改进,可以实现监听scroll滚动的具体位置等
     * 
     * @author*/
    
    public class ScrollOverListView extends ListView implements OnScrollListener {
        public static boolean canRefleash = true;
    
        private static final String TAG = "listview";
        
        /**松开更新**/
        private static final  int RELEASE_TO_REFRESH = 0;
        /**下拉更新**/
        private static final  int PULL_TO_REFRESH = 1;
        /**更新中**/
        private static final  int REFRESHING = 2;
        /**无**/
        private static final  int DONE = 3;
        /**加载中**/
        private static final  int LOADING = 4;
        /**实际的padding的距离与界面上偏移距离的比例**/
        private static final int RATIO = 3;
        
        /**是否要使用下拉刷新功能**/
        public boolean showRefresh = true;
        public boolean isDelete;
        public void setIsDelete(boolean isDelete){
            this.isDelete = isDelete;
        }
        
        private int mLastY;
        
        private int mBottomPosition;
    
        private SlideView mFocusedItemView;
        private LayoutInflater inflater;
        /**头部刷新的布局**/
        private LinearLayout headView;
        /**头部显示下拉刷新等的控件**/
        private TextView tipsTextview;
        /**刷新控件**/
        private TextView lastUpdatedTextView;
        /**箭头图标**/
        private ImageView arrowImageView;
        /**头部滚动条**/
        private ProgressBar progressBar;
        /**显示动画**/
        private RotateAnimation animation;
        /**头部回退显示动画**/
        private RotateAnimation reverseAnimation;
        /** 用于保证startY的值在一个完整的touch事件中只被记录一次**/
        private boolean isRecored;
        /**头部高度**/
        private int headContentHeight;
        /**开始的Y坐标**/
        private int startY;
        /**第一个item**/
        private int firstItemIndex;
        /**状态**/
        private int state;
        
        private boolean isBack;
        private GestureDetector gestureDetector;
        /** 空的 */
        private OnScrollOverListener mOnScrollOverListener = new OnScrollOverListener() {
    
            @Override
            public boolean onListViewTopAndPullDown(int delta) {
                return false;
            }
    
            @Override
            public boolean onListViewBottomAndPullUp(int delta) {
                return false;
            }
    
            @Override
            public boolean onMotionDown(MotionEvent ev) {
                return false;
            }
    
            @Override
            public boolean onMotionMove(MotionEvent ev, int delta) {
                return false;
            }
    
            @Override
            public boolean onMotionUp(MotionEvent ev) {
                return false;
            }
        };
    
    
        public ScrollOverListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init(context);
        }
    
        public ScrollOverListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public ScrollOverListView(Context context, PullDownView pullDownView) {
            super(context);
            isDelete = pullDownView.getIsDelete();
            init(context);
        }
    
        /**出事化控件**/
        private void init(Context context) {
            mBottomPosition = 0;
            setCacheColorHint(0);
            inflater = LayoutInflater.from(context);
    
            headView = (LinearLayout) inflater.inflate(R.layout.pull_down_head,
                    null);
            arrowImageView = (ImageView) headView
                    .findViewById(R.id.head_arrowImageView);
            arrowImageView.setMinimumWidth(70);
            arrowImageView.setMinimumHeight(50);
            progressBar = (ProgressBar) headView
                    .findViewById(R.id.head_progressBar);
            tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);
            lastUpdatedTextView = (TextView) headView
                    .findViewById(R.id.head_lastUpdatedTextView);
    
            measureView(headView);
    
            headContentHeight = headView.getMeasuredHeight();
    
            headView.setPadding(0, -1 * headContentHeight, 0, 0);
            headView.invalidate();
    
            /**列表添加头部**/
            addHeaderView(headView, null, false);
    
            setOnScrollListener(this);
    
            animation = new RotateAnimation(0, -180,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f);
            animation.setInterpolator(new LinearInterpolator());
            animation.setDuration(250);
            animation.setFillAfter(true);
            
    
            reverseAnimation = new RotateAnimation(-180, 0,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                    RotateAnimation.RELATIVE_TO_SELF, 0.5f);
            
            reverseAnimation.setInterpolator(new LinearInterpolator());
            reverseAnimation.setDuration(200);
            reverseAnimation.setFillAfter(true);
            
            state = DONE;
            gestureDetector=new GestureJudgeUtils(PublicDefine.context,new GestureJudgeUtils.OnGestureResult() {
                
                @Override
                public void onGestureResult(int direction) {
                    // TODO Auto-generated method stub
                    switch (direction) {
                    case GestureJudgeUtils.GESTURE_LEFT:
                    case GestureJudgeUtils.GESTURE_RIGHT:
                        PublicDefine.isDeleteTag=true;
                        
                        break;
                    case GestureJudgeUtils.GESTURE_DOWN:
                    case GestureJudgeUtils.GESTURE_UP:
                            PublicDefine.isDeleteTag=false;
                    default:
                        break;
                    }
                }
            }).Buile();
                    
        }
        int currentx=0;
        int currenty=0;
        /**触摸事件的处理**/
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            final int action = ev.getAction();
    
            final int y = (int) ev.getRawY();
            final int deltax=(int)ev.getRawX();
            if (action==MotionEvent.ACTION_DOWN&&PublicDefine.isDeleteTag) {
                mFocusedItemView.move();
                PublicDefine.isDeleteTag=false;
                
                return super.onTouchEvent(ev);
            }
            if (action==MotionEvent.ACTION_DOWN) {
                currentx=(int) ev.getRawX();
                currenty=(int) ev.getRawY();
            }
            
            PublicDefine.isDeleteTag=Horizontal(currentx,currenty,deltax,y);
            
                
            cancelLongPress();
            if(PublicDefine.isDeleteTag){
                switch (action) {
                case MotionEvent.ACTION_DOWN: {
                    int x = (int) ev.getX();
                    int z = (int) ev.getY();
                    int position = pointToPosition(x, z);
                    Log.e(TAG, "postion=" + position);
                    if (position != INVALID_POSITION) {
                        RouteItem data = (RouteItem) getItemAtPosition(position);
                        mFocusedItemView = data.slideView;
                        Log.e(TAG, "FocusedItemView=" + mFocusedItemView);
                    }
                }
                default:
                    break;
                }
    
                if (mFocusedItemView != null) {
                      return mFocusedItemView.onRequireTouchEvent(ev);
                }
    
                return super.onTouchEvent(ev);
            }else{
                switch (action) {
                case MotionEvent.ACTION_DOWN:   //按下的时候
                    if (firstItemIndex == 0 && !isRecored) {
                        isRecored = true;
                        startY = (int) ev.getY();
                        Log.v(TAG, "在down时候记录当前位置‘");
                    }
                    // ===========================
                    mLastY = y;
                    final boolean isHandled = mOnScrollOverListener.onMotionDown(ev);
                    if (isHandled) {
                        mLastY = y;
                        return isHandled;
                    }
                    break;
                
        
                case MotionEvent.ACTION_MOVE:    //手指正在移动的时候
                    int tempY = (int) ev.getY();
                    if (showRefresh) {
                        
                        if (!isRecored && firstItemIndex == 0) {
                            Log.v(TAG, "在move时候记录下位置");
                            isRecored = true;
                            startY = tempY;
                        }
                        if (state != REFRESHING && isRecored && state != LOADING) {
        
                            // 保证在设置padding的过程中,当前的位置一直是在head,否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
        
                            // 可以松手去刷新了
                            if (state == RELEASE_TO_REFRESH) {
        
                                setSelection(0);
        
                                // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
                                if (((tempY - startY) / RATIO < headContentHeight)
                                        && (tempY - startY) > 0) {
                                    state = PULL_TO_REFRESH;
                                    changeHeaderViewByState();
        
                                }else if (tempY - startY <= 0) {// 一下子推到顶了
                                    state = DONE;
                                    changeHeaderViewByState();
        
                                    Log.v(TAG, "由松开刷新状态转变到done状态");
                                }
        //                        else {// 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
        //                            // 不用进行特别的操作,只用更新paddingTop的值就行了
        //                        }
                            }
                            // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
                            if (state == PULL_TO_REFRESH) {
        
                                setSelection(0);
        
                                // 下拉到可以进入RELEASE_TO_REFRESH的状态
                                if ((tempY - startY) / RATIO >= headContentHeight) {
                                    state = RELEASE_TO_REFRESH;
                                    isBack = true;
                                    changeHeaderViewByState();
        
                                    Log.v(TAG, "由done或者下拉刷新状态转变到松开刷新");
                                }else if (tempY - startY <= 0) {
                                    // 上推到顶了
                                    state = DONE;
                                    changeHeaderViewByState();
        
                                    Log.v(TAG, "由DOne或者下拉刷新状态转变到done状态");
                                }
                            }
        
                            // done状态下
                            if (state == DONE) {
                                if (tempY - startY > 0) {
                                    state = PULL_TO_REFRESH;
                                    changeHeaderViewByState();
                                }
                            }
        
                            // 更新headView的size
                            if (state == PULL_TO_REFRESH) {
                                headView.setPadding(0, -1 * headContentHeight
                                        + (tempY - startY) / RATIO, 0, 0);
                            }
        
                            // 更新headView的paddingTop
                            if (state == RELEASE_TO_REFRESH) {
                                headView.setPadding(0, (tempY - startY) / RATIO
                                        - headContentHeight, 0, 0);
                            }
        
                        }
                    }
                    // ==============================================
                    final int childCount = getChildCount();
                    if (childCount == 0){
                        return super.onTouchEvent(ev);
                    }
                    final int itemCount = getAdapter().getCount() - mBottomPosition;
                    final int deltaY = y - mLastY;
                    final int lastBottom = getChildAt(childCount - 1).getBottom();
                    final int end = getHeight() - getPaddingBottom();
        
                    final int firstVisiblePosition = getFirstVisiblePosition();
        
                    final boolean isHandleMotionMove = mOnScrollOverListener
                            .onMotionMove(ev, deltaY);
        
                    if (isHandleMotionMove) {
                        mLastY = y;
                        return true;
                    }
        
                    /** 到达底部 *  到达底部的事件在另外一个类执行**/
                    if (firstVisiblePosition + childCount >= itemCount
                            && lastBottom <= end && deltaY < 0) {
                        final boolean isHandleOnListViewBottomAndPullDown;
                        isHandleOnListViewBottomAndPullDown = mOnScrollOverListener
                                .onListViewBottomAndPullUp(deltaY);
                        if (isHandleOnListViewBottomAndPullDown) {
                            mLastY = y;
                            return true;
                        }
                    }
                    break;
                
        
                case MotionEvent.ACTION_UP:    //手指抬起来的时候
                    if (state != REFRESHING && state != LOADING) {
        //                if (state == DONE) {
        //                    // 什么都不做
        //                }
                        if (state == PULL_TO_REFRESH) {
                            state = DONE;
                            changeHeaderViewByState();
                            Log.v(TAG, "由下拉刷新状态,到done状态");
                        }
        
                        if (state == RELEASE_TO_REFRESH) {
                            state = REFRESHING;
                            changeHeaderViewByState();
        
                            canRefleash = true;
        
                            Log.v(TAG, "由松开刷新状态,到done状态");
                        }
                    }
        
                    isRecored = false;
                    isBack = false;
        
                    // /======================
                    final boolean isHandlerMotionUp = mOnScrollOverListener
                            .onMotionUp(ev);
                    if (isHandlerMotionUp) {
                        mLastY = y;
                        return true;
                    }
                    break;
                
                default:
                    break;
                }
                mLastY = y;
                
                return super.onTouchEvent(ev);
            }
    //        }catch(Exception e){
    //            Log.i("test", e.getMessage());
    //            return true;
    //            
    //        }
        }
        
        private boolean Horizontal(int dx, int dy,int dx1,int dy1) {
            // TODO Auto-generated method stub
              int deltax=dx-dx1;
              int deltay=dy-dy1;
               if (Math.abs(deltax)>=Math.abs(deltay)) {
                return true;
                        
            }else {
            return false;    
            }
    
        }
    
        // =============================== public method
        /**
         * 可以自定义其中一个条目为头部,头部触发的事件将以这个为准,默认为第一个
         * 
         * @param index  正数第几个,必须在条目数范围之内
         */
        public void setTopPosition(int index) {
            if (getAdapter() == null){
                throw new NullPointerException(
                        "You must set adapter before setTopPosition!");
            }
            if (index < 0){
                throw new IllegalArgumentException("Top position must > 0");
            }
        }
    
        /**
         * 可以自定义其中一个条目为尾部,尾部触发的事件将以这个为准,默认为最后一个
         * 
         * @param index  倒数第几个,必须在条目数范围之内
         */
        public void setBottomPosition(int index) {
            if (getAdapter() == null){
                throw new NullPointerException(
                        "You must set adapter before setBottonPosition!");
            }
            if (index < 0){
                throw new IllegalArgumentException("Bottom position must > 0");
            }
    
            mBottomPosition = index;
        }
    
        /**
         * 设置这个Listener可以监听是否到达顶端,或者是否到达低端等事件</br>
         * 
         * @see OnScrollOverListener
         */
        public void setOnScrollOverListener(
                OnScrollOverListener onScrollOverListener) {
            mOnScrollOverListener = onScrollOverListener;
        }
        
        /**
         * 滚动监听接口
         * 
         * @see ScrollOverListView#setOnScrollOverListener(OnScrollOverListener)
         * 
         */
        public interface OnScrollOverListener {
            /**
             * 到达最顶部触发
             * 
             * @param delta
             *            手指点击移动产生的偏移量
             * @return
             */
            boolean onListViewTopAndPullDown(int delta);
    
    
    
            /**
             * 到达最底部触发
             * 
             * @param delta
             *            手指点击移动产生的偏移量
             * @return
             */
            boolean onListViewBottomAndPullUp(int delta);
    
            /**
             * 手指触摸按下触发,相当于{@link MotionEvent#ACTION_DOWN}
             * 
             * @return 返回true表示自己处理
             * @see View#onTouchEvent(MotionEvent)
             */
            boolean onMotionDown(MotionEvent ev);
    
            /**
             * 手指触摸移动触发,相当于{@link MotionEvent#ACTION_MOVE}
             * 
             * @return 返回true表示自己处理
             * @see View#onTouchEvent(MotionEvent)
             */
            boolean onMotionMove(MotionEvent ev, int delta);
    
            /**
             * 手指触摸后提起触发,相当于{@link MotionEvent#ACTION_UP}
             * 
             * @return 返回true表示自己处理
             * @see View#onTouchEvent(MotionEvent)
             */
            boolean onMotionUp(MotionEvent ev);
        }
    
        
        @Override
        public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2,
                int arg3) {
            firstItemIndex = firstVisiableItem;
            
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
    
        }
    
        // 此方法直接照搬自网络上的一个下拉刷新的demo,此处是“估计”headView的width以及height
        private void measureView(View child) {
            ViewGroup.LayoutParams p = child.getLayoutParams();
            if (p == null) {
                p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
            }
            int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
            int lpHeight = p.height;
            int childHeightSpec;
            if (lpHeight > 0) {
                childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
                        MeasureSpec.EXACTLY);
            } else {
                childHeightSpec = MeasureSpec.makeMeasureSpec(0,
                        MeasureSpec.UNSPECIFIED);
            }
            child.measure(childWidthSpec, childHeightSpec);
        }
        
    
        public void onRefreshComplete() {
            state = DONE;
            lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString());
            changeHeaderViewByState();
        }
    
        // 当状态改变时候,调用该方法,以更新界面
        private void changeHeaderViewByState() {
            switch (state) {
            case RELEASE_TO_REFRESH:
                arrowImageView.setVisibility(View.VISIBLE);
                progressBar.setVisibility(View.GONE);
                tipsTextview.setVisibility(View.VISIBLE);
                lastUpdatedTextView.setVisibility(View.VISIBLE);
    
                arrowImageView.clearAnimation();
                arrowImageView.startAnimation(animation);
    
                tipsTextview.setText("松开刷新");
    
                Log.v(TAG, "当前状态,松开刷新");
                break;
            case PULL_TO_REFRESH:
                progressBar.setVisibility(View.GONE);
                tipsTextview.setVisibility(View.VISIBLE);
                lastUpdatedTextView.setVisibility(View.VISIBLE);
                arrowImageView.clearAnimation();
                arrowImageView.setVisibility(View.VISIBLE);
                // 是由RELEASE_To_REFRESH状态转变来的
                if (isBack) {
                    isBack = false;
                    arrowImageView.clearAnimation();
                    arrowImageView.startAnimation(reverseAnimation);
    
                    tipsTextview.setText("下拉刷新");
                } else {
                    tipsTextview.setText("下拉刷新");
                }
                Log.v(TAG, "当前状态,下拉刷新");
                break;
    
            case REFRESHING:
    
                headView.setPadding(0, 0, 0, 0);
                progressBar.setVisibility(View.VISIBLE);
                arrowImageView.clearAnimation();
                arrowImageView.setVisibility(View.GONE);
                tipsTextview.setText("正在刷新...");
                lastUpdatedTextView.setVisibility(View.VISIBLE);
    
                Log.v(TAG, "当前状态,正在刷新...");
                break;
            case DONE:
                headView.setPadding(0, -1 * headContentHeight, 0, 0);
                progressBar.setVisibility(View.GONE);
                arrowImageView.clearAnimation();
                arrowImageView.setImageResource(R.drawable.pull_down_arrow);
                tipsTextview.setText("下拉刷新");
                lastUpdatedTextView.setVisibility(View.VISIBLE);
    
                Log.v(TAG, "当前状态,done");
                break;
            default:
                break;
            }
        }
        
        public void shrinkListItem(int position) {
            View item = getChildAt(position);
    
            if (item != null) {
                try {
                    ((SlideView) item).shrink();
                } catch (ClassCastException e) {
                    e.printStackTrace();
                }
            }
        }
    }

      ①由于这个类继承与listview,因此具有了listview常见属性与方法。

      ②由于他要记录上拉下拉刷新的方式,因此,我们这里需要用定义一些变量来保存,并且要记录他们的状态。  

      ③上拉刷新的状态是需要监听的了,怎么进行监听了,这里依照java中插件机制,依照相应的观察者(observer)模式,需要定义一个接口来监听了。

      ④为了实现动态,这里需要定义不同参数的构造函数了。

      ⑤这里是一个重点,我们定义了一个变量,接上面的论证,我们这里定义了一个变量来确定到底是调用那个触摸方法。

      ⑥一般在android中,init初始化,找到相应控件,数据加载,是一个司空见惯的方法,在这里了,我们还对相应的手势的方法进行了监听,但是后来发现在此情景下,主要是由于touch事件中,无法对手势进行监听。

      ⑦onTouchEvent事件,触摸事件,是这一切事件的重中之重,我这里首先要对其手势方向进行了监听,上文提到无法直接对手势的方向进行监听了,因此我这里粗略进行进行了判断,判断触摸按下与触摸抬起的时候,两点x轴之间的距离与两点y之间的距离孰大孰小。来判断他是竖向滚动,还是横向拖拽。倘若是横向的拖拽,进把触摸事件下放到slideview控件,由她将触摸事件进行处理,否则的话,就由此控件监听上拉下滑的刷新事件。

      ⑧与上节一样,对其滑动以后,也要对其控件的距离,控件位置进行调整,进行计算。

      ⑨这个控件本质是个列表控件,本质是对数据进行处理,因此,我们这里需要一个方法对其数据加以处理的。

      以上的内容就把slideview整合到项目中去了,其最终的效果是这样的:

      

      以上代码下载地址:

  • 相关阅读:
    crowd在更改IP后无法登录的问题
    VMware虚拟机中为Linux 添加虚拟硬盘(VirtualBox方法类似)
    虚拟机virtualbox中挂载新硬盘
    下载谷歌浏览器(Chrome)扩展离线安装包crx文件最简单的方法
    Chrome神器Vimium快捷键学习记录
    Chrome好用的扩展插件
    虚拟内存,MMU/TLB,PAGE,Cache之间关系
    ARM“庖丁解牛”之存储器管理单元MMU
    MMU——存储器管理单元
    我的vim配置---jeffy-vim-v2.3.tar
  • 原文地址:https://www.cnblogs.com/manuosex/p/3633654.html
Copyright © 2011-2022 走看看