原文链接: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;
}
/**
* 这个方法是用来设置我们拖动的方向以及侧滑的方向的
*/
@Override
public 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时会回调此方法
*/
@Override
public 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时会回调此方法
*/
@Override
public 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;
@Override
protected 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和RecyclerView
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(choseAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(choseRecycle);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public 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() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
// 获取当前点坐标封装到mCurrentPosition
mPathMeasure.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() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public 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);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public 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 {
@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;
}
}
/**
* 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;
@Override
protected 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() {
@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(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中 即标题部分 为 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;
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;
}
@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;
}
}
@Override
public 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() {
@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);
}
}
});
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) {
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() {
@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);
}
}
mItemTouchHelper.startDrag(myHolder);
return true;
}
});
myHolder.textView.setOnTouchListener(new View.OnTouchListener() {
@Override
public 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() {
@Override
public void onClick(View v) {
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);
} else {
moveOtherToMy(otherHolder);
}
startAnimation(recyclerView, currentView, targetX, targetY);
} else {
moveOtherToMy(otherHolder);
}
}
});
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) {
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() {
@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;
}
@Override
public 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 被选中时
*/
@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;
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>