Pseudo QQ message list left – swipe pop-up menu, marked read and delete
Without further ado, see this effect enchanted?
Add recyclerView to build. Gradle dependencies. Add recyclerView to build. To use a butterknife, add it here:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit: junit: 4.12'
compile 'com. Android. Support: support - v4:23.4.0'
compile 'com. Android. Support: recyclerview - v7:23.2.0'
//butterknife
compile 'com. Jakewharton: butterknife: 6.1.0'
}
Copy the code
Item, item_msg_remind. XML: message body,width: match_parent
<LinearLayout // Omit the layout Android :id="@+id/ll_msg_remind_main"> <View // omit layout Android :id="@+id/msg_remind_point"/> <LinearLayout // omit the layout Android :orientation="vertical"> <TextView // omit layout Android :id="@+id/tv_remind_title"
android:layout_weight="1"
android:text="Two balls next door."/> <TextView // omit layout Android :id="@+id/tv_remind_content"
android:layout_weight="2"
android:ellipsize="end"
android:maxLines="2"
android:text="They retracted a message and cut your dog."/> </LinearLayout> </LinearLayout> <LinearLayout // omit layout > <TextView // omit layout Android :id="@+id/tv_msg_remind_check"
android:text="Mark read"/> </LinearLayout> <LinearLayout // omit layout > <TextView // omit layout Android :id="@+id/tv_msg_remind_delete"
android:text="Delete"/>
</LinearLayout>
Copy the code
MsgRemindAdapter: extends extends Adapter<> to write your ViewHolder
public class MsgRemindAdapter extends RecyclerView.Adapter<MsgRemindAdapter.RemindViewHolder>
implements ItemSlideHelper.Callback {
private Context context;
private List<MsgVo> mDatas = new ArrayList<MsgVo>();
private RecyclerView mRecyclerView;
public MsgRemindAdapter(Context context, List<MsgVo> mDatas) {
this.context = context;
this.mDatas = mDatas;
}
Copy the code
onCreateViewHolder
@Override
public RemindViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.item_msg_remind, parent, false);
returnnew RemindViewHolder(view); Override public void onAttachedToRecyclerView(recyclerView) { super.onAttachedToRecyclerView(recyclerView); mRecyclerView = recyclerView; mRecyclerView.addOnItemTouchListener(new ItemSlideHelper(mRecyclerView.getContext(), this)); }Copy the code
OnBindViewHolder (), binding
@override public void onBindViewHolder(final RemindViewHolder holder, final int position) {/** * remindStatus */if (mDatas.get(position).isChecked()) {
holder.msgRemindPoint.setBackgroundResource(R.drawable.shape_remind_point_gray);
} else{ holder.msgRemindPoint.setBackgroundResource(R.drawable.shape_remind_point_theme); } / / message title holder. TvRemindTitle. SetText (mDatas. Get (position). The getTitle ()); / / the message content holder. TvRemindContent. SetText (mDatas. Get (position). GetContent ());Copy the code
–> Pay special attention, knock on the blackboard!! Notify in the implementation of the time, take the position to take holder. GetAdapterPosition (), and messages to be deleted, after his original position is final, so take the value of the inaccurate, crossing the line will count off group.
Message body listener, here I’m asking it to add a piece of data, replace it with the operation you need
holder.llMsgRemindMain.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { addData(mDatas.size()); }});Copy the code
Mark read listener
holder.tvMsgRemindCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mDatas.get(holder.getAdapterPosition()).setChecked(true); notifyItemChanged(holder.getAdapterPosition()); }});Copy the code
Delete message listening
holder.tvMsgRemindDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { removeData(holder.getAdapterPosition()); }});Copy the code
This method is used to calculate the distance traveled horizontally
@Override
public int getHorizontalRange(RecyclerView.ViewHolder holder) {
if(holder.itemView instanceof LinearLayout) { ViewGroup viewGroup = (ViewGroup) holder.itemView; //viewGroup contains 3 controls, namely message main item, mark read, delete, return mark read width + delete widthreturn viewGroup.getChildAt(1).getLayoutParams().width
+ viewGroup.getChildAt(2).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);
}
Copy the code
Custom ViewHolder
public class RemindViewHolder extends RecyclerView.ViewHolder { @InjectView(R.id.msg_remind_point) View msgRemindPoint; @InjectView(R.id.tv_remind_title) TextView tvRemindTitle; @InjectView(R.id.tv_remind_content) TextView tvRemindContent; @InjectView(R.id.ll_msg_remind_main) LinearLayout llMsgRemindMain; @InjectView(R.id.tv_msg_remind_check) TextView tvMsgRemindCheck; @InjectView(R.id.tv_msg_remind_delete) TextView tvMsgRemindDelete; public RemindViewHolder(View itemView) { super(itemView); ButterKnife.inject(this, itemView); }}Copy the code
Add a single piece of data
public void addData(int position) {
MsgVo vo = new MsgVo();
if (position % 2 == 1) {
vo.setChecked(false);
vo.setTitle("Two balls next door.");
vo.setContent("The other side retracts a message and cuts your dog.");
} else {
vo.setChecked(false);
vo.setTitle("Three kids on the other side.");
vo.setContent("Dark tonight, four short one, come?");
}
mDatas.add(position, vo);
notifyItemInserted(position);
}
Copy the code
Delete a single piece of data
public void removeData(int position) { mDatas.remove(position); notifyItemRemoved(position); }}Copy the code
###4. To do this tricky slide, you need an ItemSlideHelper:
/ * * * the message list left sliding menu helper classes * / public class ItemSlideHelper implements RecyclerView. OnItemTouchListener, GestureDetector.OnGestureListener { 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) { int action = MotionEventCompat.getActionMasked(e); int x = (int) e.getX(); int y = (int) e.getY(); // If RecyclerView is not idle, targetView is not emptyif(rv.getScrollState() ! = RecyclerView.SCROLL_STATE_IDLE) {if(mTargetView ! = null) {/ / hide already open smoothHorizontalExpandOrCollapse (DEFAULT_DURATION / 2); mTargetView = null; }return false; } // If the animation is running, just intercept and do nothingif(mExpandAndCollapseAnim ! = null && mExpandAndCollapseAnim.isRunning()) {return true;
}
boolean needIntercept = false;
switch (action) {
caseMotionEvent.ACTION_DOWN: mActivePointerId = MotionEventCompat.getPointerId(e, 0); mLastX = (int) e.getX(); mLastY = (int) e.getY(); /* * Return TRUE if the click did not occur in the right menu if there was an already open item, and FALSE if the right menu was clicked because the menu needs to respond to Onclick * */if(mTargetView ! = null) {return !inView(x, y); } // Find the view that needs to display the menu; 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; // If the required distance is moved, needIntercept = mIsDragging = mTargetView! = null && Math.abs(deltaX) >= mTouchSlop;break;
case MotionEvent.ACTION_CANCEL:
caseACTION_UP: /* * this is because no interception event has occurred * */if (isExpanded()) {
if (inView(x, y)) {// The ACTION_UP event will occur in the menu on the right if you go this line}else{// Intercept the event to prevent targetView from executing the onClick event needIntercept =true; } / / folding menu smoothHorizontalExpandOrCollapse (DEFAULT_DURATION / 2); } mTargetView = null;break;
}
return needIntercept;
}
private boolean isExpanded() {
returnmTargetView ! = null && mTargetView.getScrollX() == getHorizontalRange(); } private booleanisCollapsed() {
returnmTargetView ! = null && mTargetView.getScrollX() == 0; } /* * Calculate the offset of targetView according to the scrollX of targetView, so as to know that the point is in the menu * */ private BooleaninView(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) {
if(mExpandAndCollapseAnim ! = null && mExpandAndCollapseAnim.isRunning() || mTargetView == null)return; // mIsDragging is set to respond to the Fling event settingfalse
if (mGestureDetector.onTouchEvent(e)) {
mIsDragging = false;
return;
}
int x = (int) e.getX();
int y = (int) e.getY();
int action = MotionEventCompat.getActionMasked(e);
switch (action) {
caseACTION_DOWN: //RecyclerView will not forward the Down eventbreak;
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) { } /** * ScrollX * * @param delta */ private void horizontalDrag(int delta) {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); ** @param velocityX is an ACTION_UP or 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 you are halfway expanded, expand smoothlyif(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 (isCollapsed())
mTargetView = null;
}
@Override
public void onAnimationCancel(Animator animation) {
//onAnimationEnd(animation);
mExpandAndCollapseAnim = null;
}
@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, floaty); }}Copy the code
###5. Add the following to the Activity layout file:
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_msg_remind"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Copy the code
MsgRemindActivity:
/** * public class MsgRemindActivity extends Activity {@injectView (r.i.r.v_msg_remind) RecyclerView rvMsgRemind; private MsgRemindAdapter msgRemindAdapter; private List<MsgVo> mDatas; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_msg_remind); ButterKnife.inject(this); initData(); / / set the layout type for listview LinearLayoutManager rvMsgRemind. SetLayoutManager (new LinearLayoutManager (this)); rvMsgRemind.addItemDecoration(new RecyclerViewListDecoration(this, RecyclerViewListDecoration.VERTICAL_LIST)); / / fixed size recyclerview rvMsgRemind. SetHasFixedSize (true);
rvMsgRemind.setAdapter(msgRemindAdapter);
}
private void initData() {
mDatas = new ArrayList<MsgVo>();
for (int i = 'A'; i < 'G'; i++) {
MsgVo vo = new MsgVo();
if (i % 2 == 1) {
vo.setChecked(true);
vo.setTitle("Original message, read status" + (char) i);
vo.setContent("Whoo la la la la la la la la la la.");
} else {
vo.setChecked(false);
vo.setTitle("Original message, unread status");
vo.setContent("Lulu lulu lulu lulu lulu"); } mDatas.add(vo); } msgRemindAdapter = new MsgRemindAdapter(this, mDatas); }}Copy the code
###6. In the above code
rvMsgRemind.addItemDecoration(new RecyclerViewListDecoration(this,
RecyclerViewListDecoration.VERTICAL_LIST));
Copy the code
RecyclerView is a recyclerView separator, and ListView is a little different.
All right, that’s it.
### Special thanks to Hongyang old drivers to provide the license plate of RecyclerView: The Android RecyclerView fully experience the art of control “http://blog.csdn.net/lmj623565791/article/details/45059587 # # # special thanks to Android’s first, to provide ideas: http://blog.csdn.net/as_jon/article/details/51830504
# # # released demo address: http://download.csdn.net/detail/u013806766/9641654