Android进阶之路

来源:互联网 发布:网络是市场细分对 编辑:程序博客网 时间:2024/05/22 03:02

阅读之前,请喝口水,慢慢看,主要看加黑加粗字体
如果心静,15分看懂,30分实现,反之遥遥无期

这篇博客是借鉴的yanzhenjie高级猿的代码,同时是在同事的代码中进行抽离出来的,代码可以直接copy,记得不要漏下代码

Effect (如果我们不仅仅需要删除功能,我们可以在item样式里自己随便添加的!):

这里写图片描述

准备工作-build导入:

compile'com.yanzhenjie:recyclerview-swipe:1.0.0'

ItemSlideHelper(这是一个监听手势的help-可直接Copy,无需改变) :

package com.example.dow.recyclerdelete;import android.animation.Animator;import android.animation.ObjectAnimator;import android.content.Context;import android.graphics.Rect;import android.support.v4.view.GestureDetectorCompat;import android.support.v4.view.MotionEventCompat;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.view.ViewConfiguration;/** * 帮助显示左滑菜单 */public class ItemSlideHelper implements RecyclerView.OnItemTouchListener, GestureDetector.OnGestureListener {    private static final String TAG = "ItemSwipeHelper";    public boolean isUpdate= false;    private final int DEFAULT_DURATION = 200;    private View mTargetView;    private int mActivePointerId;    private int mTouchSlop;    private int mMaxVelocity;    private int mMinVelocity;    private int mLastX;    private int mLastY;    private boolean mIsDragging;    private Animator mExpandAndCollapseAnim;    private GestureDetectorCompat mGestureDetector;    private Callback mCallback;    public ItemSlideHelper(Context context, Callback callback) {        this.mCallback = callback;        //手势用于处理fling        mGestureDetector = new GestureDetectorCompat(context, this);        ViewConfiguration configuration = ViewConfiguration.get(context);        mTouchSlop = configuration.getScaledTouchSlop();        mMaxVelocity = configuration.getScaledMaximumFlingVelocity();        mMinVelocity = configuration.getScaledMinimumFlingVelocity();    }    @Override    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {        Log.d(TAG, "onInterceptTouchEvent: " + e.getAction());        int action =  MotionEventCompat.getActionMasked(e);        int x = (int) e.getX();        int y = (int) e.getY();        //如果RecyclerView滚动状态不是空闲targetView不是空        if(rv.getScrollState() != RecyclerView.SCROLL_STATE_IDLE){            if(mTargetView != null){                //隐藏已经打开                smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);                mTargetView = null;            }            return false;        }        //如果正在运行动画 ,直接拦截什么都不做        if(mExpandAndCollapseAnim != null && mExpandAndCollapseAnim.isRunning()){            return true;        }        boolean needIntercept =  false;        switch (action) {            case MotionEvent.ACTION_DOWN:                mActivePointerId = MotionEventCompat.getPointerId(e, 0);                mLastX = (int) e.getX();                mLastY = (int) e.getY();                /*                * 如果之前有一个已经打开的项目,当此次点击事件没有发生在右侧的菜单中则返回TRUE,                * 如果点击的是右侧菜单那么返回FALSE这样做的原因是因为菜单需要响应Onclick                * */                if(mTargetView != null){                    return !inView(x, y);                }                //查找需要显示菜单的view;                mTargetView = mCallback.findTargetView(x, y);                break;            case MotionEvent.ACTION_MOVE:                int deltaX = (x - mLastX);                int deltaY = (y - mLastY);                if(Math.abs(deltaY) > Math.abs(deltaX))                    return false;                //如果移动距离达到要求,则拦截                needIntercept = mIsDragging = mTargetView != null && Math.abs(deltaX) >= mTouchSlop;                break;            case MotionEvent.ACTION_CANCEL:            case MotionEvent.ACTION_UP:                /*                * 走这是因为没有发生过拦截事件                * */                if(isExpanded()){                    if (inView(x, y)) {                      // 如果走这那行这个ACTION_UP的事件会发生在右侧的菜单中                        Log.d(TAG, "click item");                        isUpdate= true;                    }else{                        //拦截事件,防止targetView执行onClick事件                        needIntercept = true;                    }                    //折叠菜单                    smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);                }                mTargetView = null;                break;        }        return  needIntercept ;    }    private boolean isExpanded() {        return mTargetView != null &&  mTargetView.getScrollX() == getHorizontalRange();    }    private boolean isCollapsed() {        return mTargetView != null && mTargetView.getScrollX() == 0;    }    /*    * 根据targetView的scrollX计算出targetView的偏移,这样能够知道这个point    * 是在右侧的菜单中    * */    private boolean inView(int x, int y) {        if (mTargetView == null)            return false;        int scrollX = mTargetView.getScrollX();        int left = mTargetView.getWidth() - scrollX;        int top = mTargetView.getTop();        int right = left + getHorizontalRange() ;        int bottom = mTargetView.getBottom();        Rect rect = new Rect(left, top, right, bottom);        return rect.contains(x, y);    }    @Override    public void onTouchEvent(RecyclerView rv, MotionEvent e) {        Log.d(TAG, "onTouchEvent: " + e.getAction());        if(mExpandAndCollapseAnim != null && mExpandAndCollapseAnim.isRunning() || mTargetView == null)            return;        //如果要响应fling事件设置将mIsDragging设为false        if (mGestureDetector.onTouchEvent(e)) {            mIsDragging = false;            return;        }        int x = (int) e.getX();        int y = (int) e.getY();        int action =  MotionEventCompat.getActionMasked(e);        switch (action) {            case MotionEvent.ACTION_DOWN:                //RecyclerView 不会转发这个Down事件                break;            case MotionEvent.ACTION_MOVE:                int deltaX = (int) (mLastX - e.getX());                if(mIsDragging) {                    horizontalDrag(deltaX);                }                mLastX = x;                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                 if(mIsDragging){                    if(!smoothHorizontalExpandOrCollapse(0) && isCollapsed())                        mTargetView = null;                    mIsDragging = false;                 }                break;        }    }    @Override    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {    }    /**     *     * 根据touch事件来滚动View的scrollX     *     * @param delta     */    private void horizontalDrag(int delta) {        int scrollX = mTargetView.getScrollX();        int scrollY = mTargetView.getScrollY();        if ((scrollX + delta) <= 0) {            mTargetView.scrollTo(0, scrollY);            return;        }        int horRange = getHorizontalRange();        scrollX += delta;        if (Math.abs(scrollX) < horRange) {            mTargetView.scrollTo(scrollX, scrollY);        } else {            mTargetView.scrollTo(horRange, scrollY);        }    }    /**     * 根据当前scrollX的位置判断是展开还是折叠     *     * @param velocityX     *  如果不等于0那么这是一次fling事件,否则是一次ACTION_UP或者ACTION_CANCEL     */    private boolean smoothHorizontalExpandOrCollapse(float velocityX) {        int scrollX = mTargetView.getScrollX();        int scrollRange = getHorizontalRange();        if (mExpandAndCollapseAnim != null)            return false;        int to = 0;        int duration = DEFAULT_DURATION;        if (velocityX == 0) {            //如果已经展一半,平滑展开            if (scrollX > scrollRange / 2) {                to = scrollRange;            }        } else {            if (velocityX > 0)                to = 0;            else                to = scrollRange;            duration = (int) ((1.f - Math.abs(velocityX) / mMaxVelocity) * DEFAULT_DURATION);        }        if(to == scrollX)            return false;        mExpandAndCollapseAnim = ObjectAnimator.ofInt(mTargetView, "scrollX", to);        mExpandAndCollapseAnim.setDuration(duration);        mExpandAndCollapseAnim.addListener(new Animator.AnimatorListener() {            @Override            public void onAnimationStart(Animator animation) {            }            @Override            public void onAnimationEnd(Animator animation) {                mExpandAndCollapseAnim = null;                if(isUpdate) {                    mCallback.updateItem();                }                isUpdate= false;                if (isCollapsed()) {                    mTargetView = null;                }                Log.d(TAG, "onAnimationEnd");            }            @Override            public void onAnimationCancel(Animator animation) {                //onAnimationEnd(animation);                mExpandAndCollapseAnim = null;                Log.d(TAG, "onAnimationCancel");            }            @Override            public void onAnimationRepeat(Animator animation) {            }        });        mExpandAndCollapseAnim.start();        return true;    }    public  int getHorizontalRange(   ) {        RecyclerView.ViewHolder viewHolder = mCallback.getChildViewHolder(mTargetView);        return mCallback.getHorizontalRange(viewHolder);    }    @Override    public boolean onDown(MotionEvent e) {        return false;    }    @Override    public void onShowPress(MotionEvent e) {    }    @Override    public boolean onSingleTapUp(MotionEvent e) {        return false;    }    @Override    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {        return false;    }    @Override    public void onLongPress(MotionEvent e) {    }    @Override    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {        if(Math.abs(velocityX) > mMinVelocity && Math.abs(velocityX) < mMaxVelocity) {            if(!smoothHorizontalExpandOrCollapse(velocityX) ) {                if(isCollapsed())                    mTargetView = null;                return true;            }        }        return false;    }    public interface Callback {        int getHorizontalRange(RecyclerView.ViewHolder holder);        RecyclerView.ViewHolder getChildViewHolder(View childView);        View findTargetView(float x, float y);        void updateItem();    }}

DividerItemDecoration(添加的间隔线条-可直接Copy,无需改变):

package com.example.dow.recyclerdelete;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */public class DividerItemDecoration extends RecyclerView.ItemDecoration {    private static final int[] ATTRS = new int[]{            android.R.attr.listDivider    };    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;    private Drawable mDivider;    private int mOrientation;    public DividerItemDecoration(Context context, int orientation) {        final TypedArray a = context.obtainStyledAttributes(ATTRS);        mDivider = a.getDrawable(0);        a.recycle();        setOrientation(orientation);    }    public void setOrientation(int orientation) {        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {            throw new IllegalArgumentException("invalid orientation");        }        mOrientation = orientation;    }    @Override    public void onDraw(Canvas c, RecyclerView parent) {        if (mOrientation == VERTICAL_LIST) {            drawVertical(c, parent);        } else {            drawHorizontal(c, parent);        }    }    public void drawVertical(Canvas c, RecyclerView parent) {        final int left = parent.getPaddingLeft();        final int right = parent.getWidth() - parent.getPaddingRight();        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int top = child.getBottom() + params.bottomMargin;            final int bottom = top + mDivider.getIntrinsicHeight();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    public void drawHorizontal(Canvas c, RecyclerView parent) {        final int top = parent.getPaddingTop();        final int bottom = parent.getHeight() - parent.getPaddingBottom();        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int left = child.getRight() + params.rightMargin;            final int right = left + mDivider.getIntrinsicHeight();            mDivider.setBounds(left, top, right, bottom);            mDivider.draw(c);        }    }    @Override    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {        if (mOrientation == VERTICAL_LIST) {            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());        } else {            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);        }    }}

MyViewHolder(item我们复用的layout-这里我们需要根据实际情况设置对应的item的id) :

package com.example.dow.recyclerdelete;import android.support.v7.widget.RecyclerView;import android.view.View;import android.widget.TextView;/** * ViewHolder复用的layout id */public class MyViewHolder extends RecyclerView.ViewHolder {    public TextView textView,del;    public MyViewHolder(View itemView) {        super(itemView);        textView = (TextView) itemView.findViewById(R.id.tv_text);        del = (TextView) itemView.findViewById(R.id.tv_delete);    }}

**RecyclerAdapter(这个要想实现自己的效果,必须修改! ) :
注意:
-其一:onCreateViewHolder中item的layout
-其二:onBindViewHolder中的数据设置
代码如下:

package com.example.dow.recyclerdelete;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.Toast;import java.util.List;/** * */public class RecyclerAdapter<T> extends RecyclerView.Adapter implements ItemSlideHelper.Callback {    private List<T> mData;    private Context mContext;    private RecyclerView mRecyclerView;    public RecyclerAdapter(List<T> mData, Context context) {        this.mData = mData;        this.mContext = context;    }    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.gx_list_item, parent, false);        MyViewHolder holder = new MyViewHolder(view);        setListener(parent, holder, viewType);        return holder;    }    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {        MyViewHolder viewHolder = (MyViewHolder) holder;        viewHolder.textView.setText(mData.get(position).toString());        viewHolder.textView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(mContext, "textView-onClick->>>" + mData.get(position).toString(), Toast.LENGTH_LONG).show();            }        });        /*viewHolder.del.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mData.remove(position);                RecyclerAdapter.this.remove(position);                //RecyclerAdapter.this.notifyDataSetChanged();                //Toast.makeText(mContext, "del-onClick->>>" + mData.get(position).toString(), Toast.LENGTH_LONG).show();            }        });*/    }    @Override    public int getItemCount() {        return mData.size();    }    public void remove(int pos) {        this.notifyItemRemoved(pos);    }    protected void setListener(final ViewGroup parent, final MyViewHolder viewHolder, int viewType) {        viewHolder.itemView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (mOnItemClickListener != null) {                    int position = viewHolder.getAdapterPosition();                    mOnItemClickListener.onItemClick(v, viewHolder, mData.get(position), position);                }            }        });        viewHolder.del.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (mOnItemClickListener != null) {                    int position = viewHolder.getAdapterPosition();                    mOnItemClickListener.delView(v, viewHolder, mData.get(position), position);                }            }        });        viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {            @Override            public boolean onLongClick(View v) {                if (mOnItemClickListener != null) {                    int position = viewHolder.getAdapterPosition();                    return mOnItemClickListener.onItemLongClick(v, viewHolder, mData.get(position), position);                }                return false;            }        });    }    public OnItemClickListener<T> mOnItemClickListener;    @Override    public void onAttachedToRecyclerView(RecyclerView recyclerView) {        super.onAttachedToRecyclerView(recyclerView);        mRecyclerView = recyclerView;        mRecyclerView.addOnItemTouchListener(new ItemSlideHelper(mRecyclerView.getContext(), this));    }    @Override    public int getHorizontalRange(RecyclerView.ViewHolder holder) {        if(holder.itemView instanceof LinearLayout){            ViewGroup viewGroup = (ViewGroup) holder.itemView;            if(viewGroup.getChildCount() == 2){                return viewGroup.getChildAt(1).getLayoutParams().width;            }        }        return 0;    }    @Override    public RecyclerView.ViewHolder getChildViewHolder(View childView) {        return mRecyclerView.getChildViewHolder(childView);    }    @Override    public View findTargetView(float x, float y) {        return mRecyclerView.findChildViewUnder(x, y);    }    @Override    public void updateItem() {        Log.e("666666","7777777777777");        this.notifyDataSetChanged();    }    public interface OnItemClickListener<T> {        void onItemClick(View view, RecyclerView.ViewHolder holder, T o, int position);        boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, T o, int position);        void delView(View view, RecyclerView.ViewHolder holder, T o, int position);    }    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {        this.mOnItemClickListener = onItemClickListener;    }}

MainActivity(这里必须要修改,因为我们有自己的item样式,还有对应的Bean-其中动画用的是默认动画,间隔线条用的是DividerItemDecoration) :

package com.example.dow.recyclerdelete;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.DefaultItemAnimator;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {    private RecyclerAdapter adapter;    private RecyclerView recyclerView;    private List<String> list = new ArrayList<>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        recyclerView = (RecyclerView) findViewById(R.id.id_rv);        initData();        adapter = new RecyclerAdapter<String>(list, this);//        recyclerView.setLayoutManager(new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false));        recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));        recyclerView.setItemAnimator(new DefaultItemAnimator());        recyclerView.setAdapter(adapter);        adapter.setOnItemClickListener(new RecyclerAdapter.OnItemClickListener() {            @Override            public void onItemClick(View view, RecyclerView.ViewHolder holder, Object o, int position) {                Toast.makeText(MainActivity.this, "onItemClick-->>>"+list.get(position), Toast.LENGTH_LONG).show();            }            @Override            public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, Object o, int position) {                Toast.makeText(MainActivity.this, "onItemLongClick-->>>"+list.get(position), Toast.LENGTH_LONG).show();                return true;//!!!!!!!!!!!!            }            @Override            public void delView(View view, RecyclerView.ViewHolder holder, Object o, int position) {                list.remove(position);                //adapter.remove(position);                //adapter.notifyDataSetChanged();            }        });    }    private void initData() {        for (int i = 1; i < 20; i++) {            list.add("第 " + i + " 项数据");        }    }}

MainActivity Xml :

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.example.dow.recyclerdelete.MainActivity">    <android.support.v7.widget.RecyclerView        android:id="@+id/id_rv"        android:layout_width="match_parent"        android:layout_height="match_parent" /></RelativeLayout>

gx_list_item Xml(以后写自己的item):

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:orientation="horizontal"    android:layout_height="50dp">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:padding="10dp"        >        <TextView            android:id="@+id/tv_text"            android:layout_width="wrap_content"            android:layout_height="wrap_content" />    </RelativeLayout>    <LinearLayout        android:layout_width="60dp"        android:orientation="horizontal"        android:layout_height="match_parent">        <TextView            android:id="@+id/tv_delete"            android:layout_width="wrap_content"            android:layout_height="match_parent"            android:layout_weight="1"            android:text="删除"            android:background="@android:color/holo_red_light"            android:gravity="center"            android:textColor="@android:color/white"            />    </LinearLayout></LinearLayout>
0 0