Android 仿网易新闻客户端分类排序功能
作者:l_215851356 发布时间:2023-12-19 13:07:52
先来看看网易新闻客户端以及自己实现的效果图,效果当然还是网易的好
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;
}
@Override
public 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
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l)
{
// ......
((GridViewSortAdapter) getAdapter()).hideView(i);
// ......
}
GridViewSortAdapter
public void hideView(int item)
{
// ......
mStartHideItemPosition = item;
notifyDataSetChanged();
}
private int mStartHideItemPosition = AdapterView.INVALID_POSITION;
@Override
public 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);
}
GridSortAdapter
public 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 仿网易新闻客户端分类排序功能网站的支持!
来源:http://blog.csdn.net/l_215851356/article/details/53884004


猜你喜欢
- 本文实例为大家分享了Unity实现10天签到系统的具体代码,供大家参考,具体内容如下实现功能:正常在游戏中签到,并把剩下的倒计时给显示出来。
- 前言我们在日常的开发过程中针对一些字段采用整型的方式去代替某些具体的含义,比如性别0代表男,1代表女。如果只是一些不会变更的转译我们可以采用
- 在进行Java打印输出,进行查看字段值的时候,觉得每次写了System.out.println之后,正式发布的时候,还得一个个的删掉,太麻烦
- C/C++的数据类型:一,整型Turbo C: [signed] int 2Byte//有符号数,-32768~32
- 本文简单分析了C/C++中常用函数的易错点,包括memset、sizeof、getchar等函数。分享给大家供大家参考之用。具体分析如下:1
- 本文实例为大家分享了Android实现简易计算功能的具体代码,供大家参考,具体内容如下效果如图:activity_main.xml<?
- 本文实例为大家分享了Java实现简单日历界面的具体代码,供大家参考,具体内容如下请使用JFrame、JPanel、JButton、JLabe
- JNI,Java Native Interface,是 native code 的编程接口。JNI 使 Java 代码程序可以与 nativ
- 一、背景SpringBoot 为我们快速开发提供了很好的架子,使得我们只需要少量配置就能开始我们的开发工作,但是当我们需要打包上传部署时,却
- 1.JavaBean转Map1.1.简介这篇博客是通过反射来进行实现转换的在学习redis中,发现了一个知识点,就是Java对象转map,视
- 引言最近在工作中结合线程池使用 InheritableThreadLocal 出现了获取线程变量“错误&rdqu
- swagger简介Swagger是一款RESTful接口的文档在线自动生成、功能测试功能框架。一个规范和完整的框架,用于生成、描述、调用和可
- 一、MessageBox弹出框MessageBox.Show(<字符串> Text, <字符串> Title, &l
- 本文实例为大家分享了java实现文件下载的具体代码,供大家参考,具体内容如下public HttpServletResponse downl
- 目录小写 string 与大写 String声明与初始化 stringstring 的不可变性正则 string 与原义 stringstr
- 本文实例讲述了C#实现基于IE内核的简单浏览器。分享给大家供大家参考。具体如下:Form1.cs如下:using System;using
- 目录服务注册服务发现服务注册引入相关依赖:<?xml version="1.0" encoding="U
- 一、PriorityQueue的数据结构JDK7中PriorityQueue(优先级队列)的数据结构是二叉堆。准确的说是一个最小堆。二叉堆是
- 1:设置注释的模板:下载此模板:codetemplates.xml搜索Dangzhang,将其改为你自己的姓名,保存打开eclipse/my
- 对智能手机有所了解的朋友都知道其中一个应用广泛的手机操作系统Android 开源手机操作系统。那么在这一系统中想要实现通话的监听功能的话,我