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
- Android进阶之路
- android进阶之路
- Android 进阶之路
- Android 进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- Android进阶之路
- webpack实现css和js文件的hash解决缓存问题
- 调用和风天气和百度语音合成接口,实现在浏览器中播报实时气象情况
- 企业信息化认知的四个误区
- 解析字符串
- myeclipse下properties文件中文乱码的解决方案
- Android进阶之路
- Android IOS WebRTC 音视频开发总结(十九)-- kurento
- the differences between groovy and java
- labview串口写数据
- tomcat 服务器配置https
- python从字符串中提取数字
- C# 学习笔记 5
- Excel 2010画箱线图 Box-Plot
- Android注解使用之Dagger2实现项目依赖关系解耦