原文链接:http://blog.csdn.net/tyk0910/article/details/51460808

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayout
        android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextView
            android:id="@+id/txt"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="10dp"android:text="切换栏目"android:textSize="15dp"/><View
            android:layout_width="match_parent"android:layout_height="1dp"android:background="@color/black"/><ScrollView
            android:layout_width="match_parent"android:layout_height="match_parent"android:scrollbars="none"><LinearLayout
                android:id="@+id/tbs_ll"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><android.support.v7.widget.RecyclerView
                    android:id="@+id/chose_recycle"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="15dp"android:layout_marginTop="15dp"android:layout_weight="1"/><LinearLayout
                    android:id="@+id/my_ll"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/chose_recycle"android:layout_centerVertical="true"android:background="@color/font_text"><TextView
                        android:id="@+id/second_txt"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="10dp"android:text="点击添加更多栏目"android:textSize="15dp"/></LinearLayout><android.support.v7.widget.RecyclerView
                    android:id="@+id/all_recycle"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/my_ll"android:layout_marginLeft="15dp"android:layout_marginTop="10dp"/></LinearLayout></ScrollView></LinearLayout>
</LinearLayout>
public interface onMoveAndSwipedListener {boolean onItemMove(int fromPosition , int toPosition);void onItemDismiss(int position);
}
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {private onMoveAndSwipedListener mAdapter;public SimpleItemTouchHelperCallback(onMoveAndSwipedListener listener) {mAdapter = listener;}/*** 这个方法是用来设置我们拖动的方向以及侧滑的方向的*/@Overridepublic int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {//如果是ListView样式的RecyclerView//设置拖拽方向为上下final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN |ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;//设置侧滑方向为从左到右和从右到左都可以final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;//将方向参数设置进去return makeMovementFlags(dragFlags, swipeFlags);}/*** 当我们拖动item时会回调此方法*/@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {//如果两个item不是一个类型的,我们让他不可以拖拽if (viewHolder.getItemViewType() != target.getItemViewType()) {return false;}//回调adapter中的onItemMove方法mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());return true;}/*** 当我们侧滑item时会回调此方法*/@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {mAdapter.onItemDismiss(viewHolder.getAdapterPosition());}}
public class WangYiActivity extends AppCompatActivity implements AllTabsAdapter.onAllTabsListener {public static List<String> choseTabs = new ArrayList<>();public static List<String> allTabs = new ArrayList<>();private RecyclerView choseRecycle, allRecycle;private ChoseTabsAdapter choseAdapter;private AllTabsAdapter   allAdapter;private LinearLayout     linearLayout;private ItemTouchHelper  mItemTouchHelper;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_wang_yi);initviews();initdatas();}private void initdatas() {choseTabs.add("头条");choseTabs.add("科技");choseTabs.add("热点");choseTabs.add("政务");choseTabs.add("移动互联");choseTabs.add("军事");choseTabs.add("历史");choseTabs.add("社会");choseTabs.add("财经");choseTabs.add("娱乐");allTabs.add("体育");allTabs.add("时尚");allTabs.add("房产");allTabs.add("论坛");allTabs.add("博客");allTabs.add("健康");allTabs.add("轻松一刻");allTabs.add("直播");allTabs.add("段子");allTabs.add("彩票");allTabs.add("直播");allTabs.add("段子");allTabs.add("彩票");allTabs.add("直播");allTabs.add("段子");allTabs.add("彩票");allTabs.add("轻松一刻");allTabs.add("直播");allTabs.add("段子");allTabs.add("彩票");allTabs.add("直播");allTabs.add("段子");allTabs.add("彩票");allTabs.add("直播");allTabs.add("段子");allTabs.add("彩票");}private void initviews() {choseTabs.clear();allTabs.clear();linearLayout = (LinearLayout) findViewById(R.id.tbs_ll);choseRecycle = (RecyclerView) findViewById(R.id.chose_recycle);allRecycle = (RecyclerView) findViewById(R.id.all_recycle);choseAdapter = new ChoseTabsAdapter(this);allAdapter = new AllTabsAdapter(this);allAdapter.setListener(this);choseRecycle.setLayoutManager(new GridLayoutManager(this, 4));allRecycle.setLayoutManager(new GridLayoutManager(this, 4));choseRecycle.addItemDecoration(new SpaceItemDecoration(15));allRecycle.addItemDecoration(new SpaceItemDecoration(15));choseRecycle.setAdapter(choseAdapter);allRecycle.setAdapter(allAdapter);//关联ItemTouchHelper和RecyclerViewItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(choseAdapter);mItemTouchHelper = new ItemTouchHelper(callback);mItemTouchHelper.attachToRecyclerView(choseRecycle);}@TargetApi(Build.VERSION_CODES.JELLY_BEAN)@Overridepublic void allTabsItemClick(final View view, final int position) {final PathMeasure mPathMeasure;final float[] mCurrentPosition = new float[2];int parentLoc[] = new int[2];linearLayout.getLocationInWindow(parentLoc);int startLoc[] = new int[2];view.getLocationInWindow(startLoc);final View startView = view;startView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));// RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(view.getWidth(), view.getHeight());Log.e("tag", startView.getWidth() + "#" + startView.getHeight());allRecycle.removeView(view);linearLayout.addView(startView);//        ImageView imageView = new ImageView(this);//        imageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));//        imageView.setImageResource(R.drawable.location_located);//        linearLayout.addView(imageView);final View endView;float toX, toY;int endLoc[] = new int[2];//进行判断int i = choseTabs.size();if (i == 0) {toX = view.getWidth();toY = view.getHeight();} else if (i % 4 == 0) {endView = choseRecycle.getChildAt(i - 4);endView.getLocationInWindow(endLoc);toX = endLoc[0] - parentLoc[0];toY = endLoc[1] + view.getHeight() - parentLoc[1];} else {endView = choseRecycle.getChildAt(i - 1);endView.getLocationInWindow(endLoc);toX = endLoc[0] + view.getWidth() - parentLoc[0];toY = endLoc[1] - parentLoc[1];}float startX = startLoc[0] - parentLoc[0];float startY = startLoc[1] - parentLoc[1];Path path = new Path();path.moveTo(startX, startY);path.lineTo(toX, toY);mPathMeasure = new PathMeasure(path, false);//属性动画实现ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());valueAnimator.setDuration(500);// 匀速插值器valueAnimator.setInterpolator(new LinearInterpolator());valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float value = (Float) animation.getAnimatedValue();// 获取当前点坐标封装到mCurrentPositionmPathMeasure.getPosTan(value, mCurrentPosition, null);startView.setTranslationX(mCurrentPosition[0]);startView.setTranslationY(mCurrentPosition[1]);Log.e("tag", mCurrentPosition[0] + "@" + mCurrentPosition[1]);}});valueAnimator.start();valueAnimator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {//默认recyclerviewe的动画allRecycle.setItemAnimator(new DefaultItemAnimator());choseRecycle.setItemAnimator(new DefaultItemAnimator());choseTabs.add(choseTabs.size(), allTabs.get(position));allTabs.remove(position);//先更新数据allAdapter.notifyDataSetChanged();choseAdapter.notifyDataSetChanged();//再更新动画allAdapter.notifyItemRemoved(position);choseAdapter.notifyItemInserted(choseTabs.size());linearLayout.removeView(startView);}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});}}

原文链接:http://www.jianshu.com/p/d30fd8da4eac

使用ItemTouchHelper高效地实现 今日头条 、网易新闻 的频道排序、移动

/*** ItemDragHelperCallback* Created by YoKeyword on 15/12/29.*/
public class ItemDragHelperCallback extends ItemTouchHelper.Callback {@Overridepublic int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {int dragFlags;RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();if (manager instanceof GridLayoutManager || manager instanceof StaggeredGridLayoutManager) {dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;} else {dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;}// 如果想支持滑动(删除)操作, swipeFlags = ItemTouchHelper.START | ItemTouchHelper.ENDint swipeFlags = 0;return makeMovementFlags(dragFlags, swipeFlags);}@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {// 不同Type之间不可移动if (viewHolder.getItemViewType() != target.getItemViewType()) {return false;}if (recyclerView.getAdapter() instanceof OnItemMoveListener) {OnItemMoveListener listener = ((OnItemMoveListener) recyclerView.getAdapter());listener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());}return true;}@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}@Overridepublic void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {// 不在闲置状态if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {if (viewHolder instanceof OnDragVHListener) {OnDragVHListener itemViewHolder = (OnDragVHListener) viewHolder;itemViewHolder.onItemSelected();}}super.onSelectedChanged(viewHolder, actionState);}@Overridepublic void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {if (viewHolder instanceof OnDragVHListener) {OnDragVHListener itemViewHolder = (OnDragVHListener) viewHolder;itemViewHolder.onItemFinish();}super.clearView(recyclerView, viewHolder);}@Overridepublic boolean isLongPressDragEnabled() {// 不支持长按拖拽功能 手动控制return false;}@Overridepublic boolean isItemViewSwipeEnabled() {// 不支持滑动功能return false;}
}
/*** ViewHolder 被选中 以及 拖拽释放 触发监听器* Created by YoKeyword on 15/12/29.*/
public interface OnDragVHListener {/*** Item被选中时触发*/void onItemSelected();/*** Item在拖拽结束/滑动结束后触发*/void onItemFinish();
}
/*** Item移动后 触发* Created by YoKeyword on 15/12/28.*/
public interface OnItemMoveListener {void onItemMove(int fromPosition, int toPosition);
}
/*** 频道 增删改查 排序* Created by YoKeyword on 15/12/29.*/
public class ChannelActivity extends AppCompatActivity {private RecyclerView mRecy;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_demo);mRecy = (RecyclerView) findViewById(R.id.recy);init();}private void init() {final List<ChannelEntity> items = new ArrayList<>();for (int i = 0; i < 18; i++) {ChannelEntity entity = new ChannelEntity();entity.setName("频道" + i);items.add(entity);}final List<ChannelEntity> otherItems = new ArrayList<>();for (int i = 0; i < 20; i++) {ChannelEntity entity = new ChannelEntity();entity.setName("其他" + i);otherItems.add(entity);}GridLayoutManager manager = new GridLayoutManager(this, 4);mRecy.setLayoutManager(manager);ItemDragHelperCallback callback = new ItemDragHelperCallback();final ItemTouchHelper helper = new ItemTouchHelper(callback);helper.attachToRecyclerView(mRecy);final ChannelAdapter adapter = new ChannelAdapter(this, helper, items, otherItems);manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {@Overridepublic int getSpanSize(int position) {int viewType = adapter.getItemViewType(position);return viewType == ChannelAdapter.TYPE_MY || viewType == ChannelAdapter.TYPE_OTHER ? 1 : 4;}});mRecy.setAdapter(adapter);adapter.setOnMyChannelItemClickListener(new ChannelAdapter.OnMyChannelItemClickListener() {@Overridepublic void onItemClick(View v, int position) {Toast.makeText(ChannelActivity.this, items.get(position).getName(), Toast.LENGTH_SHORT).show();}});}
}
/*** 拖拽排序 + 增删* Created by YoKeyword on 15/12/28.*/
public class ChannelAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements OnItemMoveListener {// 我的频道 标题部分public static final int TYPE_MY_CHANNEL_HEADER = 0;// 我的频道public static final int TYPE_MY = 1;// 其他频道 标题部分public static final int TYPE_OTHER_CHANNEL_HEADER = 2;// 其他频道public static final int TYPE_OTHER = 3;// 我的频道之前的header数量  该demo中 即标题部分 为 1private static final int COUNT_PRE_MY_HEADER = 1;// 其他频道之前的header数量  该demo中 即标题部分 为 COUNT_PRE_MY_HEADER + 1private static final int COUNT_PRE_OTHER_HEADER = COUNT_PRE_MY_HEADER + 1;private static final long ANIM_TIME = 360L;// touch 点击开始时间private long startTime;// touch 间隔时间  用于分辨是否是 "点击"private static final long SPACE_TIME = 100;private LayoutInflater mInflater;private ItemTouchHelper mItemTouchHelper;// 是否为 编辑 模式private boolean isEditMode;private List<ChannelEntity> mMyChannelItems, mOtherChannelItems;// 我的频道点击事件private OnMyChannelItemClickListener mChannelItemClickListener;public ChannelAdapter(Context context, ItemTouchHelper helper, List<ChannelEntity> mMyChannelItems, List<ChannelEntity> mOtherChannelItems) {this.mInflater = LayoutInflater.from(context);this.mItemTouchHelper = helper;this.mMyChannelItems = mMyChannelItems;this.mOtherChannelItems = mOtherChannelItems;}@Overridepublic int getItemViewType(int position) {if (position == 0) {    // 我的频道 标题部分return TYPE_MY_CHANNEL_HEADER;} else if (position == mMyChannelItems.size() + 1) {    // 其他频道 标题部分return TYPE_OTHER_CHANNEL_HEADER;} else if (position > 0 && position < mMyChannelItems.size() + 1) {return TYPE_MY;} else {return TYPE_OTHER;}}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {final View view;switch (viewType) {case TYPE_MY_CHANNEL_HEADER:view = mInflater.inflate(R.layout.item_my_channel_header, parent, false);final MyChannelHeaderViewHolder holder = new MyChannelHeaderViewHolder(view);holder.tvBtnEdit.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (!isEditMode) {startEditMode((RecyclerView) parent);holder.tvBtnEdit.setText(R.string.finish);} else {cancelEditMode((RecyclerView) parent);holder.tvBtnEdit.setText(R.string.edit);}}});return holder;case TYPE_MY:view = mInflater.inflate(R.layout.item_my, parent, false);final MyViewHolder myHolder = new MyViewHolder(view);myHolder.textView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(final View v) {int position = myHolder.getAdapterPosition();if (isEditMode) {RecyclerView recyclerView = ((RecyclerView) parent);View targetView = recyclerView.getLayoutManager().findViewByPosition(mMyChannelItems.size() + COUNT_PRE_OTHER_HEADER);View currentView = recyclerView.getLayoutManager().findViewByPosition(position);// 如果targetView不在屏幕内,则indexOfChild为-1  此时不需要添加动画,因为此时notifyItemMoved自带一个向目标移动的动画// 如果在屏幕内,则添加一个位移动画if (recyclerView.indexOfChild(targetView) >= 0) {int targetX, targetY;RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();int spanCount = ((GridLayoutManager) manager).getSpanCount();// 移动后 高度将变化 (我的频道Grid 最后一个item在新的一行第一个)if ((mMyChannelItems.size() - COUNT_PRE_MY_HEADER) % spanCount == 0) {View preTargetView = recyclerView.getLayoutManager().findViewByPosition(mMyChannelItems.size() + COUNT_PRE_OTHER_HEADER - 1);targetX = preTargetView.getLeft();targetY = preTargetView.getTop();} else {targetX = targetView.getLeft();targetY = targetView.getTop();}moveMyToOther(myHolder);startAnimation(recyclerView, currentView, targetX, targetY);} else {moveMyToOther(myHolder);}} else {mChannelItemClickListener.onItemClick(v, position - COUNT_PRE_MY_HEADER);}}});myHolder.textView.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(final View v) {if (!isEditMode) {RecyclerView recyclerView = ((RecyclerView) parent);startEditMode(recyclerView);// header 按钮文字 改成 "完成"View view = recyclerView.getChildAt(0);if (view == recyclerView.getLayoutManager().findViewByPosition(0)) {TextView tvBtnEdit = (TextView) view.findViewById(R.id.tv_btn_edit);tvBtnEdit.setText(R.string.finish);}}mItemTouchHelper.startDrag(myHolder);return true;}});myHolder.textView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if (isEditMode) {switch (MotionEventCompat.getActionMasked(event)) {case MotionEvent.ACTION_DOWN:startTime = System.currentTimeMillis();break;case MotionEvent.ACTION_MOVE:if (System.currentTimeMillis() - startTime > SPACE_TIME) {mItemTouchHelper.startDrag(myHolder);}break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:startTime = 0;break;}}return false;}});return myHolder;case TYPE_OTHER_CHANNEL_HEADER:view = mInflater.inflate(R.layout.item_other_channel_header, parent, false);return new RecyclerView.ViewHolder(view) {};case TYPE_OTHER:view = mInflater.inflate(R.layout.item_other, parent, false);final OtherViewHolder otherHolder = new OtherViewHolder(view);otherHolder.textView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {RecyclerView recyclerView = ((RecyclerView) parent);RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();int currentPiosition = otherHolder.getAdapterPosition();// 如果RecyclerView滑动到底部,移动的目标位置的y轴 - heightView currentView = manager.findViewByPosition(currentPiosition);// 目标位置的前一个item  即当前MyChannel的最后一个View preTargetView = manager.findViewByPosition(mMyChannelItems.size() - 1 + COUNT_PRE_MY_HEADER);// 如果targetView不在屏幕内,则为-1  此时不需要添加动画,因为此时notifyItemMoved自带一个向目标移动的动画// 如果在屏幕内,则添加一个位移动画if (recyclerView.indexOfChild(preTargetView) >= 0) {int targetX = preTargetView.getLeft();int targetY = preTargetView.getTop();int targetPosition = mMyChannelItems.size() - 1 + COUNT_PRE_OTHER_HEADER;GridLayoutManager gridLayoutManager = ((GridLayoutManager) manager);int spanCount = gridLayoutManager.getSpanCount();// target 在最后一行第一个if ((targetPosition - COUNT_PRE_MY_HEADER) % spanCount == 0) {View targetView = manager.findViewByPosition(targetPosition);targetX = targetView.getLeft();targetY = targetView.getTop();} else {targetX += preTargetView.getWidth();// 最后一个item可见if (gridLayoutManager.findLastVisibleItemPosition() == getItemCount() - 1) {// 最后的item在最后一行第一个位置if ((getItemCount() - 1 - mMyChannelItems.size() - COUNT_PRE_OTHER_HEADER) % spanCount == 0) {// RecyclerView实际高度 > 屏幕高度 && RecyclerView实际高度 < 屏幕高度 + item.heightint firstVisiblePostion = gridLayoutManager.findFirstVisibleItemPosition();if (firstVisiblePostion == 0) {// FirstCompletelyVisibleItemPosition == 0 即 内容不满一屏幕 , targetY值不需要变化// // FirstCompletelyVisibleItemPosition != 0 即 内容满一屏幕 并且 可滑动 , targetY值 + firstItem.getTopif (gridLayoutManager.findFirstCompletelyVisibleItemPosition() != 0) {int offset = (-recyclerView.getChildAt(0).getTop()) - recyclerView.getPaddingTop();targetY += offset;}} else { // 在这种情况下 并且 RecyclerView高度变化时(即可见第一个item的 position != 0),// 移动后, targetY值  + 一个item的高度targetY += preTargetView.getHeight();}}} else {System.out.println("current--No");}}// 如果当前位置是otherChannel可见的最后一个// 并且 当前位置不在grid的第一个位置// 并且 目标位置不在grid的第一个位置// 则 需要延迟250秒 notifyItemMove , 这是因为这种情况 , 并不触发ItemAnimator , 会直接刷新界面// 导致我们的位移动画刚开始,就已经notify完毕,引起不同步问题if (currentPiosition == gridLayoutManager.findLastVisibleItemPosition()&& (currentPiosition - mMyChannelItems.size() - COUNT_PRE_OTHER_HEADER) % spanCount != 0&& (targetPosition - COUNT_PRE_MY_HEADER) % spanCount != 0) {moveOtherToMyWithDelay(otherHolder);} else {moveOtherToMy(otherHolder);}startAnimation(recyclerView, currentView, targetX, targetY);} else {moveOtherToMy(otherHolder);}}});return otherHolder;}return null;}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {if (holder instanceof MyViewHolder) {MyViewHolder myHolder = (MyViewHolder) holder;myHolder.textView.setText(mMyChannelItems.get(position - COUNT_PRE_MY_HEADER).getName());if (isEditMode) {myHolder.imgEdit.setVisibility(View.VISIBLE);} else {myHolder.imgEdit.setVisibility(View.INVISIBLE);}} else if (holder instanceof OtherViewHolder) {((OtherViewHolder) holder).textView.setText(mOtherChannelItems.get(position - mMyChannelItems.size() - COUNT_PRE_OTHER_HEADER).getName());} else if (holder instanceof MyChannelHeaderViewHolder) {MyChannelHeaderViewHolder headerHolder = (MyChannelHeaderViewHolder) holder;if (isEditMode) {headerHolder.tvBtnEdit.setText(R.string.finish);} else {headerHolder.tvBtnEdit.setText(R.string.edit);}}}@Overridepublic int getItemCount() {// 我的频道  标题 + 我的频道.size + 其他频道 标题 + 其他频道.sizereturn mMyChannelItems.size() + mOtherChannelItems.size() + COUNT_PRE_OTHER_HEADER;}/*** 开始增删动画*/private void startAnimation(RecyclerView recyclerView, final View currentView, float targetX, float targetY) {final ViewGroup viewGroup = (ViewGroup) recyclerView.getParent();final ImageView mirrorView = addMirrorView(viewGroup, recyclerView, currentView);Animation animation = getTranslateAnimator(targetX - currentView.getLeft(), targetY - currentView.getTop());currentView.setVisibility(View.INVISIBLE);mirrorView.startAnimation(animation);animation.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {viewGroup.removeView(mirrorView);if (currentView.getVisibility() == View.INVISIBLE) {currentView.setVisibility(View.VISIBLE);}}@Overridepublic void onAnimationRepeat(Animation animation) {}});}/*** 我的频道 移动到 其他频道** @param myHolder*/private void moveMyToOther(MyViewHolder myHolder) {int position = myHolder.getAdapterPosition();int startPosition = position - COUNT_PRE_MY_HEADER;if (startPosition > mMyChannelItems.size() - 1) {return;}ChannelEntity item = mMyChannelItems.get(startPosition);mMyChannelItems.remove(startPosition);mOtherChannelItems.add(0, item);notifyItemMoved(position, mMyChannelItems.size() + COUNT_PRE_OTHER_HEADER);}/*** 其他频道 移动到 我的频道** @param otherHolder*/private void moveOtherToMy(OtherViewHolder otherHolder) {int position = processItemRemoveAdd(otherHolder);if (position == -1) {return;}notifyItemMoved(position, mMyChannelItems.size() - 1 + COUNT_PRE_MY_HEADER);}/*** 其他频道 移动到 我的频道 伴随延迟** @param otherHolder*/private void moveOtherToMyWithDelay(OtherViewHolder otherHolder) {final int position = processItemRemoveAdd(otherHolder);if (position == -1) {return;}delayHandler.postDelayed(new Runnable() {@Overridepublic void run() {notifyItemMoved(position, mMyChannelItems.size() - 1 + COUNT_PRE_MY_HEADER);}}, ANIM_TIME);}private Handler delayHandler = new Handler();private int processItemRemoveAdd(OtherViewHolder otherHolder) {int position = otherHolder.getAdapterPosition();int startPosition = position - mMyChannelItems.size() - COUNT_PRE_OTHER_HEADER;if (startPosition > mOtherChannelItems.size() - 1) {return -1;}ChannelEntity item = mOtherChannelItems.get(startPosition);mOtherChannelItems.remove(startPosition);mMyChannelItems.add(item);return position;}/*** 添加需要移动的 镜像View*/private ImageView addMirrorView(ViewGroup parent, RecyclerView recyclerView, View view) {/*** 我们要获取cache首先要通过setDrawingCacheEnable方法开启cache,然后再调用getDrawingCache方法就可以获得view的cache图片了。buildDrawingCache方法可以不用调用,因为调用getDrawingCache方法时,若果cache没有建立,系统会自动调用buildDrawingCache方法生成cache。若想更新cache, 必须要调用destoryDrawingCache方法把旧的cache销毁,才能建立新的。当调用setDrawingCacheEnabled方法设置为false, 系统也会自动把原来的cache销毁。*/view.destroyDrawingCache();view.setDrawingCacheEnabled(true);final ImageView mirrorView = new ImageView(recyclerView.getContext());Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());mirrorView.setImageBitmap(bitmap);view.setDrawingCacheEnabled(false);int[] locations = new int[2];view.getLocationOnScreen(locations);int[] parenLocations = new int[2];recyclerView.getLocationOnScreen(parenLocations);FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(bitmap.getWidth(), bitmap.getHeight());params.setMargins(locations[0], locations[1] - parenLocations[1], 0, 0);parent.addView(mirrorView, params);return mirrorView;}@Overridepublic void onItemMove(int fromPosition, int toPosition) {ChannelEntity item = mMyChannelItems.get(fromPosition - COUNT_PRE_MY_HEADER);mMyChannelItems.remove(fromPosition - COUNT_PRE_MY_HEADER);mMyChannelItems.add(toPosition - COUNT_PRE_MY_HEADER, item);notifyItemMoved(fromPosition, toPosition);}/*** 开启编辑模式** @param parent*/private void startEditMode(RecyclerView parent) {isEditMode = true;int visibleChildCount = parent.getChildCount();for (int i = 0; i < visibleChildCount; i++) {View view = parent.getChildAt(i);ImageView imgEdit = (ImageView) view.findViewById(R.id.img_edit);if (imgEdit != null) {imgEdit.setVisibility(View.VISIBLE);}}}/*** 完成编辑模式** @param parent*/private void cancelEditMode(RecyclerView parent) {isEditMode = false;int visibleChildCount = parent.getChildCount();for (int i = 0; i < visibleChildCount; i++) {View view = parent.getChildAt(i);ImageView imgEdit = (ImageView) view.findViewById(R.id.img_edit);if (imgEdit != null) {imgEdit.setVisibility(View.INVISIBLE);}}}/*** 获取位移动画*/private TranslateAnimation getTranslateAnimator(float targetX, float targetY) {TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f,Animation.ABSOLUTE, targetX,Animation.RELATIVE_TO_SELF, 0f,Animation.ABSOLUTE, targetY);// RecyclerView默认移动动画250ms 这里设置360ms 是为了防止在位移动画结束后 remove(view)过早 导致闪烁translateAnimation.setDuration(ANIM_TIME);translateAnimation.setFillAfter(true);return translateAnimation;}interface OnMyChannelItemClickListener {void onItemClick(View v, int position);}public void setOnMyChannelItemClickListener(OnMyChannelItemClickListener listener) {this.mChannelItemClickListener = listener;}/*** 我的频道*/class MyViewHolder extends RecyclerView.ViewHolder implements OnDragVHListener {private TextView textView;private ImageView imgEdit;public MyViewHolder(View itemView) {super(itemView);textView = (TextView) itemView.findViewById(R.id.tv);imgEdit = (ImageView) itemView.findViewById(R.id.img_edit);}/*** item 被选中时*/@Overridepublic void onItemSelected() {textView.setBackgroundResource(R.drawable.bg_channel_p);}/*** item 取消选中时*/@Overridepublic void onItemFinish() {textView.setBackgroundResource(R.drawable.bg_channel);}}/*** 其他频道*/class OtherViewHolder extends RecyclerView.ViewHolder {private TextView textView;public OtherViewHolder(View itemView) {super(itemView);textView = (TextView) itemView.findViewById(R.id.tv);}}/*** 我的频道  标题部分*/class MyChannelHeaderViewHolder extends RecyclerView.ViewHolder {private TextView tvBtnEdit;public MyChannelHeaderViewHolder(View itemView) {super(itemView);tvBtnEdit = (TextView) itemView.findViewById(R.id.tv_btn_edit);}}
}
/*** 频道实体类* Created by YoKeyword on 15/12/29.*/
public class ChannelEntity {private long id;private String name;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

item_my_channel_header.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="48dp"><TextView
        android:id="@+id/tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerVertical="true"android:layout_marginLeft="16dp"android:text="@string/my_cahnnel"android:textSize="16sp"/><TextView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignBottom="@id/tv"android:layout_marginLeft="16dp"android:layout_toRightOf="@id/tv"android:text="@string/tip_drag"android:textColor="@color/tip"android:textSize="12sp"/><TextView
        android:id="@+id/tv_btn_edit"android:layout_width="56dp"android:layout_height="30dp"android:layout_centerVertical="true"android:layout_alignParentRight="true"android:layout_marginRight="8dp"android:gravity="center"android:textSize="13sp"android:background="@drawable/bg_btn"android:textColor="@color/red_500"android:text="@string/edit"/><View
        android:layout_width="match_parent"android:layout_height="0.3dp"android:layout_alignParentBottom="true"android:background="@color/tip"/>
</RelativeLayout>

item_other_channel_header.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="48dp"><TextView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/other_channel"android:layout_centerVertical="true"android:layout_marginLeft="16dp"android:textSize="16sp"/><View
        android:layout_width="match_parent"android:layout_height="0.3dp"android:layout_alignParentBottom="true"android:background="@color/tip"/>
</RelativeLayout>

item_my.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextView
        android:id="@+id/tv"android:layout_width="match_parent"android:layout_height="36dp"android:layout_margin="8dp"android:background="@drawable/bg_channel"android:foreground="?attr/selectableItemBackground"android:layout_centerInParent="true"android:gravity="center"/><ImageView
        android:id="@+id/img_edit"android:layout_alignParentRight="true"android:layout_width="16dp"android:layout_height="16dp"android:src="@mipmap/ic_channel_edit"/></RelativeLayout>

item_other.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"><TextView
        android:id="@+id/tv"android:layout_width="match_parent"android:layout_height="36dp"android:layout_margin="8dp"android:background="@drawable/bg_channel"android:foreground="?attr/selectableItemBackground"android:layout_centerInParent="true"android:gravity="center"/><ImageView
        android:id="@+id/img_edit"android:layout_alignParentRight="true"android:layout_width="16dp"android:visibility="invisible"android:layout_height="16dp"/></RelativeLayout>

activity_demo.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v7.widget.RecyclerView
        android:id="@+id/recy"android:padding="8dp"android:clipChildren="false"android:clipToPadding="false"android:layout_width="match_parent"android:layout_height="match_parent"/>
</FrameLayout>

新闻阅读器频道管理

RecyclerView ItemTouchHelper相关推荐

  1. RecyclerView实现条目拖拽,左滑、右滑移除效果

    对于android开发者来说RecyclerView应该已经很熟悉了,项目中基本都是使用RecyclerView来实现列表效果,这里要实现的是RecyclerView的条目拖拽.左滑.右滑移除效果,这 ...

  2. Android 控件 RecyclerView

    [Android 控件 RecyclerView] 概述 RecyclerView是什么 从Android 5.0开始,谷歌公司推出了一个用于大量数据展示的新控件RecylerView,可以用来代替传 ...

  3. 安卓开发仿微信图片拖拽_Android 仿微信朋友圈发表图片拖拽和删除功能

    朋友圈实现原理 我们使用 Android Device Monitor 来分析朋友圈发布图片的界面实现原理.如果需要分析其他应用的界面实现也是采用这种方法哦. 打开 Android Device Mo ...

  4. Android 仿微信朋友圈发表图片拖拽和删除功能

    朋友圈实现原理 我们使用 Android Device Monitor 来分析朋友圈发布图片的界面实现原理.如果需要分析其他应用的界面实现也是采用这种方法哦. 打开 Android Device Mo ...

  5. 安卓开发仿微信图片拖拽_仿微信朋友圈发表图片拖拽和删除功能

    原标题:仿微信朋友圈发表图片拖拽和删除功能 中国联通在香港公布了上市公司2017年中期业绩.2017年上半年,公司主要业绩指标持续向好,收入稳步回升,服务收入达到人民币1,241.1亿元,同比增长3. ...

  6. Android之仿B612咔叽滤镜列表操作

    本文主要记录模仿B612咔叽 6.2.0 版本里的滤镜操作 B612咔叽 6.2.0 版本里的滤镜的操作特点- 长按某一个滤镜收藏(点击应用这个是肯定的) - 收藏后列表最左边出现红色的竖条块,点击可 ...

  7. android仿小红书图片拖拽(改进版,仿微信朋友圈拖拽删除)

    一.小红书效果 上面三个图是小红书发布动态的时候选择好图片后,长按图片进行排序的效果.长按后,选择的图片浮起,随手指左右移动,靠近左右边缘的时候,整体的条目可以左右滚动,再将手指选择的图片发到合适的位 ...

  8. Android 高仿腾讯新闻频道定制页面

    先上效果图 移除频道的动画效果模仿得不是很像,如果有更好的实现方法可以在下面留言告诉我. 页面效果拆解 部分已选频道位置固定,不能拖动 已选频道可以长按拖拽改变顺序,长按后背景色改变,删除按钮隐藏,原 ...

  9. Android实现RecyclerView侧滑删除和长按拖拽-ItemTouchHelper

    RecyclerView这个被誉为ListView和GirdView的替代品,它的用法在之前的一篇博文中就已经讲过了,今天我们就来实现RecyclerView的侧滑删除和长按拖拽功能,实现这两个功能我 ...

最新文章

  1. 鲲鹏高校行太原站来袭,两大课程一站式掌握未来潮流
  2. Oracle 一些常用的数据字典
  3. fastjson的@JSONField注解
  4. TortoiseGit 更新远程仓库最新代码到本地仓库_入门试炼_05
  5. SpringIOC容器-对象依赖
  6. [费用流]洛谷 P2053 修车(zkw费用流模版)
  7. 开关灯(c语言数据结构习题)
  8. 本特利330906-02-12-05-02-CN传感器
  9. VBV缓冲区大小-MPEG2规范
  10. 关于ROHDESCHWARZ公司电流探头EZ-17系数修正的说明
  11. _itemmod_enchant_groups
  12. 和计算机 玩猜拳游戏的程序,计算机猜拳游戏
  13. vss备份,使用批处理,每次只能备份当前打开的项目,怎么才能备份所有的项目呢...
  14. 8bit位图保存为1bit
  15. python画五角星和六角星程序_python画五角星和六角星程序
  16. Linux:安装和配置tomcat详细教程
  17. 使用酷狗音乐api实现歌曲的搜索和下载
  18. 无线路由器“无线漫游”
  19. 上海亚商投顾:市场呈现窄幅震荡 新能源类行业受热炒
  20. 基于Spark GraphX的图形数据分析

热门文章

  1. 直面故障,我们该怎么做?
  2. linux上修改ssh密码和mysql密码
  3. 跨平台使用exp/imp进行数据库转移时出现丢失对象的原因
  4. gitlab远程提交
  5. 图片远程保存,浏览器直接下载
  6. Java工程师之SpringBoot系列教程前言目录
  7. NowCoder110E Pocky游戏 状压DP
  8. 推荐:浏览器是怎样工作的?
  9. Oracle 截取字符串,取系统时间
  10. Dynamics CRM2013 任务列表添加自定义按钮