Android 仿今日头条、网易新闻的频道管理
2017-09-18 14:13
357 查看
最近做新闻类型的项目,用到了频道管理,点击删除排序,拖动排序。来分享一下
下面上代码:
MainActivity 布局
MainActivity 中的代码:
下面是关键:
适配器:
上面提供了 排序后获取数据的方法:
一个关键的帮助类 ItemTouchHelper:
好了 关键的代码都贴出来了,想要完成代码看下面
源码在这里
下面上代码:
MainActivity 布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="soexample.umeng.com.myapplication.MainActivity" android:orientation="vertical" > <FrameLayout 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> </LinearLayout>
MainActivity 中的代码:
/** * 频道 增删改查 排序 */ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); showDialog(); } private RecyclerView mRecy; private ChannelAdapter adapter; private Dialog dialog;//对话框 public void showDialog() { if (dialog == null) { dialog = new Dialog(MainActivity.this, R.style.custom_dialog); dialog.setCanceledOnTouchOutside(true); //获取对话框的窗口,并设置窗口参数 Window win = dialog.getWindow(); WindowManager.LayoutParams params = new WindowManager.LayoutParams(); // 不能写成这样,否则Dialog显示不出来 // LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT); //对话框窗口的宽和高 params.width = WindowManager.LayoutParams.MATCH_PARENT; params.height = WindowManager.LayoutParams.MATCH_PARENT; //对话框窗口显示的位置 params.x = 120; params.y = 590; win.setAttributes(params); //设置对话框布局 dialog.setContentView(R.layout.activity_channel); mRecy = (RecyclerView)dialog.findViewById(R.id.recy); 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); adapter = new ChannelAdapter(MainActivity.this, helper, items, otherItems,dialog); manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public 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() { @Override public void onItemClick(View v, int position) { Toast.makeText(MainActivity.this, items.get(position).getName(), Toast.LENGTH_SHORT).show(); } }); } dialog.show(); } /** * 隐藏对话框 */ public void dismiss() { //隐藏对话框之前先判断对话框是否存在,以及是否正在显示 if (dialog != null && dialog.isShowing()) { dialog.dismiss(); } } }
下面是关键:
适配器:
/** * 拖拽排序 + 增删 * */ 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中 即标题部分 为 1 private static final int COUNT_PRE_MY_HEADER = 1; // 其他频道之前的header数量 该demo中 即标题部分 为 COUNT_PRE_MY_HEADER + 1 private 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; private OnMyChannelItemC mChannelItemC ; private Dialog dialog;//对话框 private boolean flag=false; private Context context; public ChannelAdapter(Context context, ItemTouchHelper helper, List<ChannelEntity> mMyChannelItems, List<ChannelEntity> mOtherChannelItems,Dialog dialog) { this.mInflater = LayoutInflater.from(context); this.mItemTouchHelper = helper; this.mMyChannelItems = mMyChannelItems; this.mOtherChannelItems = mOtherChannelItems; this.dialog=dialog; this.context=context; } @Override public 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; } } /** * 获取频道列表 已选的 */ public List<ChannelEntity> getChannnelLst() { return mMyChannelItems; } /** * 获取频道列表 未选的 */ public List<ChannelEntity> getChannnelLstother() { return mOtherChannelItems; } View view; @Override public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) { 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() { @Override public 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); } } }); holder.llback.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //隐藏对话框之前先判断对话框是否存在,以及是否正在显示 if (dialog != null && dialog.isShowing()) { dialog.dismiss(); /** * 如果没有点击完成,默认切换 */ 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() { @Override public void onClick(final View v) { int position = myHolder.getAdapterPosition(); // 是否为 编辑 模式 if (isEditMode) { //是否需要保存 flag = true; 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, recyclerView, currentView, targetX, targetY); // startAnimation(recyclerView, currentView, targetX, targetY); Log.e(" 已选 1", "/*/*/*******************************"); } else { Log.e(" 已选 2", "/*/*/*******************************"); moveMyToOther(myHolder, recyclerView, currentView, 0, 0); } // // mChannelItemC.onItemClick(v, position - COUNT_PRE_MY_HEADER, flag); } else { //// 我的频道之前的header数量 该demo中 即标题部分 为 1 COUNT_PRE_MY_HEADER mChannelItemClickListener.onItemClick(v, position - COUNT_PRE_MY_HEADER); } } }); /** * 长按******************* */ myHolder.textView.setOnLongClickListener(new View.OnLongClickListener() { @Override public 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); } } else //是否需要保存 flag = true; int position = myHolder.getAdapterPosition(); /** * 处理第一个和第二个不可以拖动 */ if (position != 1 && position != 2) { mItemTouchHelper.startDrag(myHolder); } // mChannelItemC.onItemClick(v, position - COUNT_PRE_MY_HEADER, flag); return true; } }); myHolder.textView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { int position = myHolder.getAdapterPosition(); if (isEditMode) { switch (MotionEventCompat.getActionMasked(event)) { case MotionEvent.ACTION_DOWN: startTime = System.currentTimeMillis(); break; case MotionEvent.ACTION_MOVE: if (System.currentTimeMillis() - startTime > SPACE_TIME) { /** * 处理第一个和第二个不可以拖动 */ if (position!=1&&position!=2){ 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() { @Override public void onClick(View v) { //是否需要保存 flag=true; RecyclerView recyclerView = ((RecyclerView) parent); RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); int currentPiosition = otherHolder.getAdapterPosition(); // 如果RecyclerView滑动到底部,移动的目标位置的y轴 - height View 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.height int firstVisiblePostion = gridLayoutManager.findFirstVisibleItemPosition(); if (firstVisiblePostion == 0) { // FirstCompletelyVisibleItemPosition == 0 即 内容不满一屏幕 , targetY值不需要变化 // // FirstCompletelyVisibleItemPosition != 0 即 内容满一屏幕 并且 可滑动 , targetY值 + firstItem.getTop if (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); Log.e("1","/*/*/*******************************"); } else { moveOtherToMy(otherHolder); Log.e("2","/*/*/*******************************"); } startAnimation(recyclerView, currentView, targetX, targetY); } else { Log.e("3","/*/*/*******************************"); moveOtherToMy(otherHolder); } // mChannelItemC.onItemClick(v,currentPiosition - COUNT_PRE_MY_HEADER,flag); } }); return otherHolder; } return null; } @Override public 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); } } } @Override public int getItemCount() { // 我的频道 标题 + 我的频道.size + 其他频道 标题 + 其他频道.size return 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() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { viewGroup.removeView(mirrorView); if (currentView.getVisibility() == View.INVISIBLE) { currentView.setVisibility(View.VISIBLE); } } @Override public void onAnimationRepeat(Animation animation) { } }); } /** * 我的频道 移动到 其他频道 第一个条目和第二个条目不移动 * * @param myHolder */ private void moveMyToOther(MyViewHolder myHolder,RecyclerView recyclerView,View currentView,int targetX,int targetY) { int position = myHolder.getAdapterPosition(); int startPosition = position - COUNT_PRE_MY_HEADER; if (startPosition > mMyChannelItems.size() - 1) { return; }else if (startPosition==0||startPosition==1){ // 第一个条目和第二个条目不移动 }else { // 是否为 编辑 模式 if (isEditMode) { ChannelEntity item = mMyChannelItems.get(startPosition); mMyChannelItems.remove(startPosition); mOtherChannelItems.add(0, item); notifyItemMoved(position, mMyChannelItems.size() + COUNT_PRE_OTHER_HEADER); startAnimation( recyclerView, currentView, targetX, targetY); }else { 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() { @Override public 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; } /** * 移动过程中更新适配器********************************************************* 处理移动后的数据 ******************************************************************** * @param fromPosition * @param toPosition */ @Override public void onItemMove(int fromPosition, int toPosition) { if (toPosition==1||toPosition==2){ return; } Log.e("fromPosition",fromPosition+"/****************************"); Log.e("toPosition",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); //是否需要保存 flag=true; // mChannelItemC.onItemClick(view,toPosition - COUNT_PRE_MY_HEADER,flag); } /** * 开启编辑模式 默认第一条和第二条不显示可编辑 * * @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) { if (i==1||i==2){ imgEdit.setVisibility(View.GONE); }else { 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; } /** * 接口回调 */ public interface OnMyChannelItemClickListener { void onItemClick(View v, int position); } public void setOnMyChannelItemClickListener(OnMyChannelItemClickListener listener) { this.mChannelItemClickListener = listener; } public interface OnMyChannelItemC { void onItemClick(View v, int position,boolean a); } public void setOnMyChannelItemC(OnMyChannelItemC listener) { this.mChannelItemC = 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 被选中时 */ @Override public void onItemSelected() { textView.setBackgroundResource(R.drawable.bg_channel_p); } /** * item 取消选中时 */ @Override public 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; LinearLayout llback; public MyChannelHeaderViewHolder(View itemView) { super(itemView); tvBtnEdit = (TextView) itemView.findViewById(R.id.tv_btn_edit); llback= (LinearLayout) itemView.findViewById(R.id.ll_back); } } }
上面提供了 排序后获取数据的方法:
/** * 获取频道列表 已选的 */ public List<ChannelEntity> getChannnelLst() { return mMyChannelItems; } /** * 获取频道列表 未选的 */ public List<ChannelEntity> getChannnelLstother() { return mOtherChannelItems; }
一个关键的帮助类 ItemTouchHelper:
/** * ItemDragHelperCallback * */ public class ItemDragHelperCallback extends ItemTouchHelper.Callback { @Override public 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.END int swipeFlags = 0; return makeMovementFlags(dragFlags, swipeFlags); } @Override public 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; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { } @Override public 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); } @Override public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { if (viewHolder instanceof OnDragVHListener) { OnDragVHListener itemViewHolder = (OnDragVHListener) viewHolder; itemViewHolder.onItemFinish(); } super.clearView(recyclerView, viewHolder); } @Override public boolean isLongPressDragEnabled() { // 不支持长按拖拽功能 手动控制 return false; } @Override public boolean isItemViewSwipeEnabled() { // 不支持滑动功能 return false; } }
好了 关键的代码都贴出来了,想要完成代码看下面
源码在这里
相关文章推荐
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android使用RecyclerView实现今日头条频道管理功能
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 仿今日头条频道管理(上)(GridView之间Item的移动和拖拽)
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 仿今日头条频道管理(上)(GridView之间Item的移动和拖拽)
- Android 仿今日头条频道管理(上)(GridView之间Item的移动和拖拽)
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 频道管理仿今日头条
- Android GridView 仿今日头条频道管理
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (能够拖动的GridView)附源代码DEMO
- Android 高仿 频道管理----网易、今日头条、腾讯视频 (可以拖动的GridView)附源码DEMO