样式效果

         

1、创建自定义GridView

/*** 作者:created by meixi* 邮箱:15913707499@163.com* 日期:2019/5/31 13*/public class DragGridView extends GridView {/** 点击时候的X位置 */public int downX;/** 点击时候的Y位置 */public int downY;/** 点击时候对应整个界面的X位置 */public int windowX;/** 点击时候对应整个界面的Y位置 */public int windowY;/** VIEW相对自己的X */private int win_view_x;/**VIEW相对自己的Y*/private int win_view_y;/** 长按时候对应postion */public int dragPosition;/** Up后对应的ITEM的Position */private int dropPosition;/** 开始拖动的ITEM的Position*/private int startPosition;/** item高 */private int itemHeight;/** item宽 */private int itemWidth;/** 拖动的时候对应ITEM的VIEW */private View dragImageView = null;/** 长按的时候ITEM的VIEW*/private ViewGroup dragItemView = null;/** WindowManager管理器 */private WindowManager windowManager = null;/** */private WindowManager.LayoutParams windowParams = null;/** item总量*/private int itemTotalCount;/** 一行的ITEM数量*/private int nColumns = 4;/** 行数 */private int nRows;/** 剩余部分 */private int Remainder;/** 是否在移动 */private boolean isMoving = false;/** */private int holdPosition;/** 拖动的时候放大的倍数 */private double dragScale = 1.2D;/** 震动器  */private Vibrator mVibrator;/** 每个ITEM之间的水平间距 */private int mHorizontalSpacing = 15;/** 每个ITEM之间的竖直间距 */private int mVerticalSpacing = 15;/** 移动时候最后个动画的ID */private String LastAnimationID;public DragGridView(Context context) {super(context);init(context);}public DragGridView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(context);}public DragGridView(Context context, AttributeSet attrs) {super(context, attrs);init(context);}/*** dip转为 px*/public  int dip2px(Context context, float dipValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dipValue * scale + 0.5f);}public void init(Context context){mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);//将布局文件中设置的间距dip转为pxmHorizontalSpacing = dip2px(context, mHorizontalSpacing);}/** 在ScrollView内,所以要进行计算高度 */@Overridepublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);super.onMeasure(widthMeasureSpec, expandSpec);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {if (ev.getAction() == MotionEvent.ACTION_DOWN) {downX = (int) ev.getX();downY = (int) ev.getY();windowX = (int) ev.getX();windowY = (int) ev.getY();setOnItemClickListener(ev);}return super.dispatchTouchEvent(ev);}/** 停止拖动 ,释放并初始化 */private void stopDrag() {if (dragImageView != null) {windowManager.removeView(dragImageView);dragImageView = null;}}/** 在拖动的情况更新View的位置 */private void onDrag(int x, int y , int rawx , int rawy) {if (dragImageView != null) {windowParams.alpha = 0.6f;windowParams.x = rawx - win_view_x;windowParams.y = rawy - win_view_y;windowManager.updateViewLayout(dragImageView, windowParams);}}/***创建窗口对象、添加我们要移动的View* @param dragBitmap* @param x* @param y*/public void startDrag(Bitmap dragBitmap, int x, int y) {stopDrag();windowParams = new WindowManager.LayoutParams();// 获取WINDOW界面的//Gravity.TOP|Gravity.LEFT;这个必须加windowParams.gravity = Gravity.TOP | Gravity.LEFT;//得到要移动的View左上角相对于屏幕的坐标windowParams.x = x - win_view_x;windowParams.y = y  - win_view_y;//设置拖拽item的宽和高windowParams.width = (int) (dragScale * dragBitmap.getWidth());// 放大dragScale倍,可以设置拖动后的倍数windowParams.height = (int) (dragScale * dragBitmap.getHeight());// 放大dragScale倍,可以设置拖动后的倍数this.windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;this.windowParams.format = PixelFormat.TRANSLUCENT;this.windowParams.windowAnimations = 0;ImageView iv = new ImageView(getContext());iv.setImageBitmap(dragBitmap);windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);// "window"windowManager.addView(iv, windowParams);dragImageView = iv;}/** 隐藏 放下 的ITEM*/private void hideDropItem() {((DragAdapter) getAdapter()).setShowDropItem(false);}/** 在松手下放的情况,更新界面 */private void onDrop(int x, int y) {// 根据拖动到的x,y坐标获取拖动位置下方的ITEM对应的POSTIONint tempPostion = pointToPosition(x, y);
//    if (tempPostion != AdapterView.INVALID_POSITION) {dropPosition = tempPostion;DragAdapter mDragAdapter = (DragAdapter) getAdapter();//显示刚拖动的ITEMmDragAdapter.setShowDropItem(true);//刷新适配器,让对应的ITEM显示mDragAdapter.notifyDataSetChanged();
//    }}/*** 长按点击监听* @param ev*/public void setOnItemClickListener(final MotionEvent ev) {setOnItemLongClickListener(new OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {int x = (int) ev.getX();// 长按事件的X位置int y = (int) ev.getY();// 长按事件的y位置startPosition = position;// 第一次点击的postiondragPosition = position;if (startPosition <= 1) {//前2个默认不点击、可以设置return false;}ViewGroup dragViewGroup = (ViewGroup) getChildAt(dragPosition - getFirstVisiblePosition());TextView dragTextView = (TextView)dragViewGroup.findViewById(R.id.text_item);dragTextView.setSelected(true);dragTextView.setEnabled(false);itemHeight = dragViewGroup.getHeight();itemWidth = dragViewGroup.getWidth();itemTotalCount = DragGridView.this.getCount();// 如果特殊的这个不等于拖动的那个,并且不等于-1if (dragPosition != AdapterView.INVALID_POSITION) {// 释放的资源使用的绘图缓存。如果你调用buildDrawingCache()手动没有调用setDrawingCacheEnabled(真正的),你应该清理缓存使用这种方法。win_view_x = windowX - dragViewGroup.getLeft();//VIEW相对自己的X,半斤win_view_y = windowY - dragViewGroup.getTop();//VIEW相对自己的y,半斤dragItemView = dragViewGroup;dragViewGroup.destroyDrawingCache();dragViewGroup.setDrawingCacheEnabled(true);Bitmap dragBitmap = Bitmap.createBitmap(dragViewGroup.getDrawingCache());mVibrator.vibrate(50);//设置震动时间startDrag(dragBitmap, (int)ev.getRawX(),  (int)ev.getRawY());hideDropItem();dragViewGroup.setVisibility(View.INVISIBLE);isMoving = false;return true;}return false;}});}@Overridepublic boolean onTouchEvent(MotionEvent ev) {if (dragImageView != null && dragPosition != AdapterView.INVALID_POSITION) {// 移动时候的对应x,y位置int x = (int) ev.getX();int y = (int) ev.getY();switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:downX = (int) ev.getX();windowX = (int) ev.getX();downY = (int) ev.getY();windowY = (int) ev.getY();break;case MotionEvent.ACTION_MOVE:onDrag(x, y ,(int) ev.getRawX() , (int) ev.getRawY());if (!isMoving){OnMove(x, y);}if (pointToPosition(x, y) != AdapterView.INVALID_POSITION){break;}break;case MotionEvent.ACTION_UP:stopDrag();onDrop(x, y);requestDisallowInterceptTouchEvent(false);break;default:break;}}return super.onTouchEvent(ev);}/** 移动的时候触发,移动所有改变的Item*/public void OnMove(int x, int y) {// 拖动的VIEW下方的POSTIONint dPosition = pointToPosition(x, y);// 判断下方的POSTION是否是最开始2个不能拖动的if (dPosition > 1) {if ((dPosition == -1) || (dPosition == dragPosition)){return;}dropPosition = dPosition;if (dragPosition != startPosition){dragPosition = startPosition;}int movecount;//拖动的=开始拖的,并且 拖动的 不等于放下的if ((dragPosition == startPosition) || (dragPosition != dropPosition)){//移需要移动的动ITEM数量movecount = dropPosition - dragPosition;}else{//移需要移动的动ITEM数量为0movecount = 0;}if(movecount == 0){return;}int movecount_abs = Math.abs(movecount);if (dPosition != dragPosition) {//dragGroup设置为不可见ViewGroup dragGroup = (ViewGroup) getChildAt(dragPosition);dragGroup.setVisibility(View.INVISIBLE);float to_x = 1;//移动的X偏移量float to_y;// 移动的Y偏移量//x_vlaue移动的距离百分比(相对于自己长度的百分比)float x_vlaue = ((float) mHorizontalSpacing / (float) itemWidth) + 1.0f;//y_vlaue移动的距离百分比(相对于自己宽度的百分比)float y_vlaue = ((float) mVerticalSpacing / (float) itemHeight) + 1.0f;Log.d("x_vlaue", "x_vlaue = " + x_vlaue);for (int i = 0; i < movecount_abs; i++) {to_x = x_vlaue;to_y = y_vlaue;//向右if (movecount > 0) {// 判断是不是同一行的holdPosition = dragPosition + i + 1;if (dragPosition / nColumns == holdPosition / nColumns) {to_x = - x_vlaue;to_y = 0;} else if (holdPosition % 4 == 0) {to_x = 3 * x_vlaue;to_y = - y_vlaue;} else {to_x = - x_vlaue;to_y = 0;}}else{//向左,下移到上,右移到左holdPosition = dragPosition - i - 1;if (dragPosition / nColumns == holdPosition / nColumns) {to_x = x_vlaue;to_y = 0;} else if((holdPosition + 1) % 4 == 0){to_x = -3 * x_vlaue;to_y = y_vlaue;}else{to_x = x_vlaue;to_y = 0;}}ViewGroup moveViewGroup = (ViewGroup) getChildAt(holdPosition);Animation moveAnimation = getMoveAnimation(to_x, to_y);moveViewGroup.startAnimation(moveAnimation);//如果是最后一个移动的,那么设置他的最后个动画ID为LastAnimationIDif (holdPosition == dropPosition) {LastAnimationID = moveAnimation.toString();}moveAnimation.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {isMoving = true;}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {// 如果为最后个动画结束,那执行下面的方法if (animation.toString().equalsIgnoreCase(LastAnimationID)) {DragAdapter mDragAdapter = (DragAdapter) getAdapter();mDragAdapter.exchange(startPosition,dropPosition);startPosition = dropPosition;dragPosition = dropPosition;isMoving = false;}}});}}}}/** 获取移动的动画 */public Animation getMoveAnimation(float toXValue, float toYValue) {TranslateAnimation mTranslateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0F,Animation.RELATIVE_TO_SELF,toXValue,Animation.RELATIVE_TO_SELF, 0.0F,Animation.RELATIVE_TO_SELF, toYValue);// 当前位置移动到指定位置mTranslateAnimation.setFillAfter(true);// 设置一个动画效果执行完毕后,View对象保留在终止的位置。mTranslateAnimation.setDuration(300L);return mTranslateAnimation;}
}

2、activity实现

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {private MyGridView mOtherGv;private DragGridView mUserGv;private List<String> mUserList = new ArrayList<>();private List<String> mOtherList = new ArrayList<>();private OtherAdapter mOtherAdapter;private DragAdapter  mUserAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}public void initView() {mUserGv = (DragGridView) findViewById(R.id.userGridView);mOtherGv = (MyGridView) findViewById(R.id.otherGridView);mUserList.add("推荐");mUserList.add("热点");mUserList.add("上海");mUserList.add("时尚");mUserList.add("科技");mUserList.add("体育");mUserList.add("军事");mUserList.add("财经");mUserList.add("网络");mOtherList.add("汽车");mOtherList.add("房产");mOtherList.add("社会");mOtherList.add("情感");mOtherList.add("女人");mOtherList.add("旅游");mOtherList.add("健康");mOtherList.add("美女");mOtherList.add("游戏");mOtherList.add("数码");mOtherList.add("娱乐");mOtherList.add("探索");mUserAdapter = new DragAdapter(this, mUserList,true);mOtherAdapter = new OtherAdapter(this, mOtherList,false);mUserGv.setAdapter(mUserAdapter);mOtherGv.setAdapter(mOtherAdapter);mUserGv.setOnItemClickListener(this);mOtherGv.setOnItemClickListener(this);}

demo云盘链接:https://pan.baidu.com/s/1iKAHJ3yrUeece1Yi1dsSEw

云盘密码交流:QQ1085220040

demo链接:https://download.csdn.net/download/meixi_android/11224016

Android 频道管理,可拖动item排列,删除,添加相关推荐

  1. android 部分区域点击,Android编程实现ListView中item部分区域添加点击事件功能

    本文实例讲述了Android编程实现ListView中item部分区域添加点击事件功能.分享给大家供大家参考,具体如下: 需求如题目:Android listview中item部分区域添加点击事件,在 ...

  2. Android频道管理集成

    前言 最近开发的项目中有类似网易新闻的频道管理,在完成项目后,我将频道管理单独抽取成Library,方便以后开发,也把总结到的一点知识分享出来.先看看,我的频道管理有什么特点吧. 特点 1.支持固定频 ...

  3. Android 频道管理仿今日头条

    导入依赖 在项目的build.gradle导入 allprojects {repositories {jcenter() //下面这一行就是 maven { url "https://jit ...

  4. Android 仿今日头条频道管理(下)(GridView之间Item的移动和拖拽)

    前言 上篇博客我们说到了今日头条频道管理的操作交互体验,我也介绍了2个GridView之间Item的相互移动.详情请參考:Android 仿今日头条频道管理(上)(GridView之间Item的移动和 ...

  5. 今日头条 频道管理(删除、添加、拖动)

    频道管理共分为两部分: 一.频道的删除和添加 二.频道的拖动 一.频道的删除和添加 利用监听来进行动画的执行. 动画:以item本身创建Bitmap, 然后放入顶层ViewGroup 执行动画并监听A ...

  6. Android 仿今日头条、网易新闻的频道管理

    最近做新闻类型的项目,用到了频道管理,点击删除排序,拖动排序.来分享一下 下面上代码: MainActivity 布局 <?xml version="1.0" encodin ...

  7. Android 仿今日头条的频道管理

    //主布局 activity_main.xml<?xml version="1.0" encoding="utf-8"?> <Relative ...

  8. Android仿头条频道管理

    XML文件: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:and ...

  9. android新闻管理,Android资讯新闻类App(头条、网易等),频道管理集成之数据库存储...

    Android资讯新闻类App(头条.网易等),频道管理集成之数据库存储 发布时间:2019-01-16 19:55, 浏览次数:305 , 标签: Android App * 经常看新闻类的大家都知 ...

最新文章

  1. c++作业5 9.22
  2. html偷拍代码,一段植入木马的html代码
  3. mysql重复make_Mysql5.6 make 错误以及解决办法
  4. sigmoid激活函数
  5. 2022年CXO领导力峰会暨IT东方会技术高管年会
  6. 总结:Postman测试、IP:POST测试、Postman转换到python测试(Linux下的docker应用部署web容器并存储数据到mysql,调用API)
  7. 刷题笔记——青蛙跳台阶问题汇总
  8. UnityShader笔记第三课-MVP矩阵原理-M矩阵
  9. php获取七牛上传token失效,上传文件到七牛时,bad token了怎么处理?
  10. 【C++】利用DFS求解水洼数目问题
  11. 今天安装了VS2008中文版SP1。
  12. python计算ks
  13. IntelliJ IDEA 2018.2.2 x64安装破解教程
  14. Excel转储mysql_小程序解析excel表格并存储到云数据库
  15. linux4.1内核配置以及编译及千兆网卡dp83867网卡驱动移植
  16. Android App 优化之 Layout 怎么摆
  17. React学习笔记二:实现一个数字时钟
  18. Eureka Client 注册报 registration status: 204
  19. Linux:刻录u盘,格式化u盘
  20. 安装ngrok和voila(windows系统)

热门文章

  1. GY歌谣之读懂每行代码(飞智) 2020 10 16 Duplicate keys detected
  2. 前端学习(2174):打包文件的分析
  3. “约见”面试官系列之常见面试题之第七十一篇之let和var和const区别(建议收藏)
  4. 前端学习(2158):webpack配置文件的分离
  5. “睡服”面试官系列第二篇之promise(建议收藏学习)
  6. 前端学习(1637):前端系列实战课程之调试问题和规范
  7. 第十期:过去50年间,十大热门语言及发明者大盘点
  8. 纯CSS实现锚点跳转位置上下偏移的办法
  9. Vh和Vw的简介和使用
  10. 如何禁用计算机的服务,如何彻底禁用电脑中的迅雷服务XLservicePlatform