时间:2021-05-21
先来看看网易新闻客户端以及自己实现的效果图,效果当然还是网易的好
gridviewsort.gif
如何实现拖拽一个Item
用WindowManager添加一个ImageView,并且将这个ImageView的显示图片设置成被拖拽item的截图,截图可以通过View的getDrawingCache获得。拖拽的时候,隐藏原始的item。处理触摸事件的ActionMove,调整ImageView的位置,跟随手指移动。在ActionUp的时候removeView
GridView
@Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { // 至少有两个item的时候,才有排序 if (getChildCount() >= 2) { mView = view; // 在调用getDrawingCache必须先调用 view.setDrawingCacheEnabled(true); // 获取截图并设置 Bitmap bitmap = view.getDrawingCache(); mDragItemView.setImageBitmap(bitmap); // 设置拖拽的imageview的params mDragItemLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; mDragItemLayoutParams.width = bitmap.getWidth(); mDragItemLayoutParams.height = bitmap.getHeight(); mDragItemLayoutParams.x = (mDownX - mDragItemLayoutParams.width / 2); mDragItemLayoutParams.y = (mDownY - mDragItemLayoutParams.height / 2); // 设置拖拽imageview的中心位于长按点击点 mDragItemLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE //不接受按键事件 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE // 不接收触摸事件 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON // 保持常亮 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; // place the window within the entire screen, ignoring decorations around the border (such as the status bar) mDragItemLayoutParams.format = PixelFormat.TRANSLUCENT; mDragItemLayoutParams.windowAnimations = 0; // 往WindowManager中添加拖拽的View mWindowManager.addView(mDragItemView, mDragItemLayoutParams); ((GridViewSortAdapter) getAdapter()).init(); ((GridViewSortAdapter) getAdapter()).hideView(i); Log.d(TAG, "long click = " + i); mDragStarted = true; } return true; }@Overridepublic boolean onTouchEvent(MotionEvent ev){ switch (ev.getAction() & ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: mDownX = (int) ev.getRawX(); mDownY = (int) ev.getRawY(); break; case MotionEvent.ACTION_MOVE: if (mDragStarted) { // 保持中心 mDragItemLayoutParams.x = (int) (ev.getRawX() - mDragItemView.getWidth() / 2); mDragItemLayoutParams.y = (int) (ev.getRawY() - mDragItemView.getHeight() / 2); // 更新params mWindowManager.updateViewLayout(mDragItemView, mDragItemLayoutParams); // ...... } break; case MotionEvent.ACTION_UP: // ...... break; } return super.onTouchEvent(ev);}如何实现隐藏拖拽的Item
在开始拖拽的时候,把隐藏的item的position告诉Adapter,调用Adapter的notifyDataSetChanged刷新数据,在getView方法中判断当前的构建的item的position是不是需要隐藏的position是的话就设置view为inVisible
GridView
@Overridepublic boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l){ // ...... ((GridViewSortAdapter) getAdapter()).hideView(i); // ......}GridViewSortAdapterpublic void hideView(int item){ // ...... mStartHideItemPosition = item; notifyDataSetChanged();}private int mStartHideItemPosition = AdapterView.INVALID_POSITION;@Overridepublic View getView(int position, View convertView, ViewGroup parent){ ViewHolder holder = null; if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.view_item_grid_view_sort, null); holder = new ViewHolder(); holder.title = (TextView) convertView.findViewById(R.id.view_item_grid_view_sort_title); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.title.setText(mTypeTitle.get(position)); if (mStartHideItemPosition == position) { convertView.setVisibility(View.INVISIBLE); } else { convertView.setVisibility(View.VISIBLE); } return convertView;}如何知道当前拖拽到哪一个item之上
要想在拖拽到其他item上面时互换位置,那必须得知道当前拖拽到了哪一个item之上。GrideView提供了一个方法叫pointToPosition,可以在处理触摸事件的ACTION_MOVE时,获取手指触摸的x,y来得到当前拖拽到item之上的position。这里需要注意的一点是,在拖拽的过程,同一个item的position是不会变的,除非调用了Adapter的notifyDataSetChanged,position才会重新计算。比如position为2的item,在拖拽的过程无论怎么动画移动位置,他的position都是2,知道一次拖拽结束,ActionUp的时候,会调用notifyDataSetChanged
GridView
@Override public boolean onTouchEvent(MotionEvent ev) { case MotionEvent.ACTION_MOVE: if (mDragStarted) { // ...... int position = pointToPosition((int) ev.getX(), (int) ev.getY()); // ...... } break;}如何实现动画
一个item需要水平以及垂直需要移动的距离可以事先先计算出来,其实水平距离不管怎么样一定会是GridView一个单元格的宽度加上水平间距,垂直距离无论如何都是一个单元格的高度加上垂直距离,宽度非常好取,高度的话,这里默认item 的高度和单元格的高度相同。
GridViewSortAdapter
View view = mGridView.getChildAt(0);mTranslateX = view.getWidth() + mHorizontalSpace;mTranslateY = view.getHeight() + mVerticalSpace;当拖拽到其他item之上时,开始动画
SortGridView
if (position != AdapterView.INVALID_POSITION && !((GridViewSortAdapter) getAdapter()).isInAnimation()){ Log.d(TAG, "position = " + position); ((GridViewSortAdapter) getAdapter()).swap(position);}GridSortAdapterpublic void swap(int position){ mAnimatorSetList.clear(); int r_p = mPositionList.indexOf(position); Log.d(TAG, "r_p = " + r_p); if (mCurrentHideItemPosition < r_p) { for (int i = mCurrentHideItemPosition + 1; i <= r_p; i++) { View v = mGridView.getChildAt(mPositionList.get(i)); if (i % mColsNum == 0 && i > 0) { startMoveAnimation(v, v.getTranslationX() + mTranslateX * (mColsNum - 1), v.getTranslationY() - mTranslateY); } else { startMoveAnimation(v, v.getTranslationX() - mTranslateX, 0); } } } else if (mCurrentHideItemPosition > r_p) { for (int i = r_p; i < mCurrentHideItemPosition; i++) { View v = mGridView.getChildAt(mPositionList.get(i)); if ((i + 1) % mColsNum == 0) { startMoveAnimation(v, v.getTranslationX() - mTranslateX * (mColsNum - 1), v.getTranslationY() + mTranslateY); } else { startMoveAnimation(v, v.getTranslationX() + mTranslateX, 0); } } } resetPositionList(); int value = mPositionList.get(mStartHideItemPosition); if (mStartHideItemPosition < r_p) { mPositionList.add(r_p + 1, value); mPositionList.remove(mStartHideItemPosition); } else if (mStartHideItemPosition > r_p) { mPositionList.add(r_p, value); mPositionList.remove(mStartHideItemPosition + 1); } mCurrentHideItemPosition = r_p;}public boolean isInAnimation(){ return mInAnimation;}private void resetPositionList(){ mPositionList.clear(); for (int i = 0; i < mGridView.getChildCount(); i++) { mPositionList.add(i); }}private void startMoveAnimation(View myView, float x, float y){ AnimatorSet set = new AnimatorSet(); set.playTogether( ObjectAnimator.ofFloat(myView, "translationX", myView.getTranslationX(), x), ObjectAnimator.ofFloat(myView, "translationY", myView.getTranslationY(), y) ); set.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { mInAnimation = true; } @Override public void onAnimationEnd(Animator animator) { mInAnimation = false; } @Override public void onAnimationCancel(Animator animator) { } @Override public void onAnimationRepeat(Animator animator) { } }); mAnimatorSetList.add(set); set.setDuration(150).start();}这里我主要解释一下代码中 mPositionList这个列表的作用,之前说过一次拖拽的时候,item的position是不会变化的。
假设有一组数据
a b c d
e f g h
i j k l
此时mPositionList的内容就是 0 1 2 3 4 5 6 7 8 9 10 11 12
现在将c拖拽到g上,拖拽完成之后的数据应该是,未释放手指
a b d e
f g c h
i j k l
此时mPositionList的内容就是 0 1 2 4 5 6 7 3 8 9 10 11 12
紧接着,继续拖拽c到e上,你会发现调用pointToPosition方法得到的position是5,但是e现在的索引是4
因此你只需要调用
mPositionList.indexOf(pointToPosition(x,y))就能得到真实的item的position
其他
如果把GridView的列数变成1那么似曾相识啊
gridviewex.gif
源码地址
https://github.com/jiahuanyu/android-example-code/tree/master/app/src/main/java/com/github/jiahuanyu/example/ui/dragsortgird
以上所述是小编给大家介绍的Android 仿网易新闻客户端分类排序功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
关于实现网易新闻客户端的界面,以前写过很多博客,请参考:Android实现网易新闻客户端效果Android实现网易新闻客户端侧滑菜单(一)Android实现网易
很多刚接触网易新闻客户端的用户,不知道在其中如何修改正文字体?接下来就为你们讲解网易新闻客户端中修改正文字体的流程介绍。 1、打开网易新闻客户端,进入网易新
前面已经讲过通过三方开源库SlideMenu来实现这种效果,请参考Android实现网易新闻客户端侧滑菜单(一)今天通过自定义View来实现这种功能。代码如下:
你们知道在网易新闻客户端中如何修改头像吗?不太明白的用户就随着小编一起去下面看看网易新闻客户端中修改头像的详细流程介绍。 1、首先,下载安软市场最新版的网易
网易新闻的评论只有管理员才能删,用户是没有权限,用户可以致电网易客服,让其删除。网易新闻是网易倾力打造的精品应用,已然成为国内第一新闻客户端,因体验最流畅、新闻