zoukankan      html  css  js  c++  java
  • 高仿微信对话列表滑动删除效果

    前言

    用过微信的都知道。微信对话列表滑动删除效果是非常不错的,这个效果我们也能够有。

    思路事实上非常easy,弄个ListView。然后里面的每一个item做成一个能够滑动的自己定义控件就可以。由于ListView是上下滑动而item是左右滑动,因此会有滑动冲突。或许你须要了解下android中点击事件的派发流程,请參考Android源代码分析-点击事件派发机制。我的解决思路是这种:重写ListView的onInterceptTouchEvent方法,在move的时候做推断,假设是左右滑动就返回false。否则返回true;重写SlideView(即自己定义item控件)的onTouchEvent方法来处理滑动。

    整个思路没有问题。滑动冲突也攻克了,但是ListView无法得到焦点了,也就是ListView无法处理点击事件了。让我们回忆下问题出在哪里:我的理解是这种。上述处理滑动本身没有问题,但是有一个副作用。就是会让外层View失去焦点且无法处理点击事件。

    常见的滑动冲突场景。比方launcher内部嵌入ListView却是没有问题的,由于这个时候launcher不须要获得焦点,须要获得焦点的是内部的ListView。

    因此,上述处理方式对于外部须要获得焦点的情况(比方外部是ListView)就不太适合了。于是我就和ttdevs探讨,发现他採用了第二种思路。我从来没有想过还能够这样玩。以下介绍他的思路。

    新的思路

    不考虑那么复杂,不採用主流玩法,全部的事件均由外层的ListView做拦截,同一时候把事件传递给SlideView做滑动,这样的实现的确能够达到效果,并且代码非常easy,根本不须要处理什么复杂的滑动冲突。

    效果

    以下分别为微信和高仿效果

    代码分析

    先看SlideView是怎样实现的

    看layout xml:

    <com.macc.firstsecretary_UI.ListViewCompat
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#fff4f7f9"
            android:cacheColorHint="#00000000"
            android:divider="#dddbdb"
            android:dividerHeight="1.0px"
            android:drawSelectorOnTop="false"
            android:listSelector="@android:color/transparent"
            android:scrollbars="none" />


    再看com.macc.firstsecretary_UI.ListViewCompat类的代码:

    private static final String TAG = "ListViewCompat";
    
        private SlideView mFocusedItemView;
    
        public ListViewCompat(Context context) {
            super(context);
        }
    
        public ListViewCompat(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public ListViewCompat(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public void shrinkListItem(int position) {
            View item = getChildAt(position);
    
            if (item != null) {
                try {
                    ((SlideView) item).shrink();
                } catch (ClassCastException e) {
                    e.printStackTrace();
                }
            }
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                int x = (int) event.getX();
                int y = (int) event.getY();
                int position = pointToPosition(x, y);
                Log.e(TAG, "postion=" + position);
                if (position != INVALID_POSITION) {
                    Message data = (Message) getItemAtPosition(position);
                    mFocusedItemView = data.getSlideView();
                    Log.e(TAG, "FocusedItemView=" + mFocusedItemView);
                }
            }
            default:
                break;
            }
    
            if (mFocusedItemView != null) {
                mFocusedItemView.onRequireTouchEvent(event);
            }
    
            return true;
        }


    再看SlideView.java:

    public class SlideView extends LinearLayout {
    
        private static final String TAG = "SlideView";
    
        private Context mContext;
        private LinearLayout mViewContent;
        private RelativeLayout mHolder;
        private Scroller mScroller;
        private OnSlideListener mOnSlideListener;
    
        private int mHolderWidth = 120;
    
        private int mLastX = 0;
        private int mLastY = 0;
        private static final int TAN = 2;
    
        private  boolean isScroller=false;//是否已经滑动
        public interface OnSlideListener {
            public static final int SLIDE_STATUS_OFF = 0;
            public static final int SLIDE_STATUS_START_SCROLL = 1;
            public static final int SLIDE_STATUS_ON = 2;
    
            /**
             * @param view current SlideView
             * @param status SLIDE_STATUS_ON or SLIDE_STATUS_OFF
             */
            public void onSlide(View view, int status);
        }
    
        public SlideView(Context context) {
            super(context);
            initView();
        }
    
        public SlideView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView();
        }
    
        private void initView() {
            mContext = getContext();
            mScroller = new Scroller(mContext);
    
            setOrientation(LinearLayout.HORIZONTAL);
            View.inflate(mContext, R.layout.slide_view_merge, this);
            mViewContent = (LinearLayout) findViewById(R.id.view_content);
            mHolderWidth = Math.round(TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources()
                            .getDisplayMetrics()));
        }
    
        public void setButtonText(CharSequence text) {
            ((TextView)findViewById(R.id.delete)).setText(text);
        }
    
        public void setContentView(View view) {
            mViewContent.addView(view);
        }
    
        public void setOnSlideListener(OnSlideListener onSlideListener) {
            mOnSlideListener = onSlideListener;
        }
    
        public void shrink() {
            if (getScrollX() != 0) {
                this.smoothScrollTo(0, 0);
            }
        }
    
        public void onRequireTouchEvent(MotionEvent event) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            int scrollX = getScrollX();
            Log.d(TAG, "x=" + x + "  y=" + y);
    
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                if (mOnSlideListener != null) {
                    mOnSlideListener.onSlide(this,
                            OnSlideListener.SLIDE_STATUS_START_SCROLL);
                }
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
                if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {
                    break;
                }
    
                int newScrollX = scrollX - deltaX;
                if (deltaX != 0) {
                	if(isScroller){
                    	this.shrink();
                	}else{
    	                if (newScrollX < 0) {
    	                    newScrollX = 0;
    	                } else if (newScrollX > mHolderWidth) {
    	                    newScrollX = mHolderWidth;
    	                }
    	                this.scrollTo(newScrollX, 0);
                	}
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                int newScrollX = 0;
                if (scrollX - mHolderWidth * 0.75 > 0) {
                    newScrollX = mHolderWidth;
                }
                if(isScroller){
                	this.shrink();
                	isScroller=false;
                }else{
    	            this.smoothScrollTo(newScrollX, 0);
    	            if (mOnSlideListener != null) {
    	                mOnSlideListener.onSlide(this,
    	                        newScrollX == 0 ?

    OnSlideListener.SLIDE_STATUS_OFF : OnSlideListener.SLIDE_STATUS_ON); } isScroller=true; } break; } default: break; } mLastX = x; mLastY = y; } private void smoothScrollTo(int destX, int destY) { // 缓慢滚动到指定位置 int scrollX = getScrollX(); int delta = destX - scrollX; mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3); invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } }



    上述代码做了非常具体的说明,这就是滑动控件的完整代码,大家要明确的是:你所加入的view都是加在SlideView的子View : view_content中的,而不是直接加在SlideView中,仅仅有这样我们才方便做滑动效果。

    最后一步我们来看看适配器里面的代码:

    public class Carpa_MySelf_MessageCenterAdapter extends BaseAdapter implements OnSlideListener,OnClickListener{
    
    	private LayoutInflater inflater;
    	private List<Message> messages;
    	private Context context;
    	private SlideView mSlideView;
    	private int position;//删除位置数据
    	private Handler handler;
    	public Carpa_MySelf_MessageCenterAdapter(Context context,ArrayList<Message> messages,Handler handler){
    		setData(messages);
    		this.context=context;
    		inflater=LayoutInflater.from(context);
    		this.handler=handler;
    	}
    	public void setData(ArrayList<Message> messages){
    		if(messages==null){
    			this.messages=new ArrayList<Message>();
    		}else{
    			this.messages=messages;
    		}
    	}
    	public void setPosition(int position){
    		this.position=position;
    	}
    	@Override
    	public int getCount() {
    		// TODO Auto-generated method stub
    		return messages.size();
    	}
    
    	@Override
    	public Object getItem(int position) {
    		// TODO Auto-generated method stub
    		return messages.get(position);
    	}
    
    	@Override
    	public long getItemId(int position) {
    		// TODO Auto-generated method stub
    		return position;
    	}
    
    	@Override
    	public View getView(int position, View convertView, ViewGroup parent) {
    		 ViewHolder holder;
             SlideView slideView = (SlideView) convertView;
             if (slideView == null) {
                 View itemView = inflater.inflate(R.layout.carpa_myself_message_center_item, null);
    
                 slideView = new SlideView(context);
                 slideView.setContentView(itemView);
    
                 holder = new ViewHolder(slideView);
                 slideView.setOnSlideListener(Carpa_MySelf_MessageCenterAdapter.this);
                 slideView.setTag(holder);
             } else {
                 holder = (ViewHolder) slideView.getTag();
             }
             Message msgMessage=messages.get(position);
             msgMessage.setSlideView(slideView);
             msgMessage.getSlideView().shrink();
             String sourceString=msgMessage.getSourceStr();
             holder.tvContent.setText("内容:"+msgMessage.getContentStr());
             holder.tvTime.setText(UtilTools.fromatDate(msgMessage.getTimeStr()));
             holder.deleteHolder.setOnClickListener(Carpa_MySelf_MessageCenterAdapter.this);
             if(sourceString.equals("Traffic")){
            	 holder.tvSource.setText("信息来源:66");
            	 holder.iView.setBackgroundResource(R.drawable.carpa_wz);
             }else if(sourceString.equals("DaiJia")){
            	 holder.tvSource.setText("信息来源:99");
            	 holder.iView.setBackgroundResource(R.drawable.car_deldrive);
             }else if(sourceString.equals("Nianjian")){
            	 holder.tvSource.setText("信息来源:33");
            	 holder.iView.setBackgroundResource(R.drawable.car_yearcheck);
             }else if(sourceString.equals("JiaSZ")){
            	 holder.tvSource.setText("信息来源:88");
            	 holder.iView.setBackgroundResource(R.drawable.car_zjbl);
             }else if(sourceString.equals("HKJiaSZ")){
            	 holder.tvSource.setText("信息来源:11");
            	 holder.iView.setBackgroundResource(R.drawable.car_hongkong);
             }
             return slideView;
    	}
    	class ViewHolder {
    		public ImageView iView;
            public TextView tvSource;
            public TextView tvTime;
            public TextView tvContent;
            public ViewGroup deleteHolder;
    
            ViewHolder(View view) {
            	iView=(ImageView)view.findViewById(R.id.message_center_iv);
            	tvSource = (TextView) view.findViewById(R.id.message_center_source);
            	tvTime = (TextView) view.findViewById(R.id.message_center_time);
            	tvContent = (TextView) view.findViewById(R.id.message_center_content);
                deleteHolder = (ViewGroup)view.findViewById(R.id.holder);
            }
        }
    	@Override
    	public void onClick(View v) {
    		// TODO Auto-generated method stub
            if (v.getId() == R.id.holder) {
                Log.e("info", "onClick v=" + v);
    //            messages.remove(position);
    //            this.notifyDataSetChanged();
                handler.sendEmptyMessage(Tab_MySelf_MessageCenter.HANDLER_DELETE);
            }
    	}
    	@Override
    	public void onSlide(View view, int status) {
    		// TODO Auto-generated method stub
            if (mSlideView != null && mSlideView != view) {
            	mSlideView.shrink();
            }
    
            if (status == SLIDE_STATUS_ON) {
            	mSlideView = (SlideView) view;
            }
    	}


    代码已贴完成!

    仅供參考,谢谢!

  • 相关阅读:
    Django(69)最好用的过滤器插件Django-filter
    Django(68)drf分页器的使用
    Django(67)drf搜索过滤和排序过滤
    SweetAlert使用
    虚拟环境之间批量pip安装包迁移
    ubuntu 18.04 安装uwsgi 和nginx
    ubuntu 18.04安装mysql及常见问题处理
    ubuntu 18.04安装virtualenv和virtualenvwrapper安装及使用
    滚动视差stellar.js
    JMeter之使用技巧
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6871645.html
Copyright © 2011-2022 走看看