频道管理共分为两部分:

一、频道的删除和添加
二、频道的拖动

一、频道的删除和添加

利用监听来进行动画的执行。
动画:以item本身创建Bitmap, 然后放入顶层ViewGroup 执行动画并监听Animation(动画为TranslateAnimation 移动)

代码:

public class MyActivity extends Activity{private DragGrid userGridView;private OtherGridView otherGridView;private DragGridAdapter adapter;private ArrayList<String> data1 = null;private ArrayList<String> data2 = null;private OtherAdapter otherAdapter;//1、防止报java.lang.ArrayIndexOutOfBoundsException 异常,用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引//主要是当连续点击那个还没有移除item的时候, adapter.remove回报这个错private boolean isMove = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.main);initView();initListener();}private void initView(){userGridView = (DragGrid)findViewById(R.id.userGridView);otherGridView = (OtherGridView) findViewById(R.id.otherGridView);data1 = new ArrayList<String>();data2 = new ArrayList<String>();String[] s = new String[]{"如果当时", "多余的解释", "有何不可", "坏孩子", "清明雨上", "城府", "认错", "内线", "星座书上"};for(int i = 0;i < s.length;i ++){data1.add(s[i]);}String[] ss = new String[]{"等到烟火清凉", "山水之间", "七夕", "有桃花", "惊鸿一面", "隐隐约约", "宇宙之大", "梧桐灯", "弹指一挥间","胡萝卜须", "幻听", "对话老师", "伴虎", "闺蜜", "装糊涂", "play with style", "心疼你的过去", "全球变冷", "亲情式的爱情"};for(int i = 0;i < ss.length;i ++){data2.add(ss[i]);}adapter = new DragGridAdapter(this, data1);otherAdapter = new OtherAdapter(this, data2);userGridView.setAdapter(adapter);otherGridView.setAdapter(otherAdapter);}private void initListener(){userGridView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,final int position, long id) {// TODO Auto-generated method stubif(isMove){return;}if(position > 1){final ImageView moveImage = getView(view);if(moveImage != null){TextView nowTextView = (TextView) view.findViewById(R.id.text_item);final int[] startCoord = new int[2];//getLocationInWindow:获取在整个窗口内的绝对坐标//将view的左上角坐标存入数组中.此坐标是相对当前activity而言.nowTextView.getLocationInWindow(startCoord);//setVisible():显示动画要移动的位置 otherAdapter.setVisible(false);otherAdapter.add(data1.get(position));//postDelayed():延时50L之后执行new Handler().postDelayed(new Runnable(){@Overridepublic void run() {// TODO Auto-generated method stubint[] endCoord = new int[2];otherGridView.getChildAt(otherGridView.getLastVisiblePosition()).getLocationInWindow(endCoord);adapter.setRemove(position);moveAnim(moveImage, startCoord, endCoord, userGridView);}}, 50L);}}}});otherGridView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,final int position, long id) {// TODO Auto-generated method stubif (isMove) {return;}if (position > 1) {final ImageView moveImage = getView(view);if (moveImage != null) {TextView nowTextView = (TextView) view.findViewById(R.id.text_item);final int[] startCoord = new int[2];nowTextView.getLocationInWindow(startCoord);adapter.setVisible(false);adapter.add(data2.get(position));new Handler().postDelayed(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubint[] endCoord = new int[2];userGridView.getChildAt(userGridView.getLastVisiblePosition()).getLocationInWindow(endCoord);otherAdapter.setRemove(position);moveAnim(moveImage, startCoord, endCoord, otherGridView);}}, 50L);}}}});}/* 移动动画*/private void moveAnim(View view, int[] start, int[] end, final GridView clickGridView){//getViewGroup、getMoveView :因为Bitmap 不支持Animation动画 所以用控件包含Bitmap 用控件来展示动画 final ViewGroup viewGroup = getViewGroup();final View moveView = getMoveView(viewGroup, view);//创建移动动画TranslateAnimation moveAnimation = new TranslateAnimation(start[0], end[0],start[1], end[1]);moveAnimation.setDuration(300L);AnimationSet moveAnimationSet = new AnimationSet(true);moveAnimationSet.setFillAfter(false);//动画效果执行完毕后,View对象不保留在终止的位置moveAnimationSet.addAnimation(moveAnimation);moveView.startAnimation(moveAnimationSet);moveAnimationSet.setAnimationListener(new AnimationListener() {public void onAnimationStart(Animation animation) {// TODO Auto-generated method stubisMove = true;}public void onAnimationRepeat(Animation animation) {// TODO Auto-generated method stub}public void onAnimationEnd(Animation animation) {// TODO Auto-generated method stub//删除添加的控件viewGroup.removeView(moveView);if(clickGridView instanceof DragGrid){otherAdapter.setVisible(true);otherAdapter.notifyDataSetChanged();adapter.remove();}else {adapter.setVisible(true);adapter.notifyDataSetChanged();otherAdapter.remove();}isMove = false;}});}/* 把Bitmap添加进ViewGroup*/private View getMoveView(ViewGroup group, View view){group.addView(view);LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);view.setLayoutParams(params);return view;}/* 获取ViewGroup */private ViewGroup getViewGroup(){//getDecorView():decorView是window中的最顶层viewViewGroup group = (ViewGroup)getWindow().getDecorView();LinearLayout moveLinearLayout = new LinearLayout(this);LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);moveLinearLayout.setLayoutParams(params);group.addView(moveLinearLayout);return moveLinearLayout;}/* 用来获取绘制的图片*/private ImageView getView(View view){view.destroyDrawingCache();view.setDrawingCacheEnabled(true);Bitmap cache = Bitmap.createBitmap(view.getDrawingCache());view.setDrawingCacheEnabled(false);ImageView iv = new ImageView(this);iv.setImageBitmap(cache);return iv;}}

二、频道的拖动

思路:重写GridView

通过setOnItemLongClickListener()长时间按住触动 创建窗口 进行拖动

1、创建移动窗口

利用WindowManager WindowManager.LayoutParams 进行窗口创建

2、拖动频道移动

通过TranslateAnimation进行频道移动

public class DragGrid extends GridView {/** 每个ITEM之间的水平间距 */private int mHorizontalSpacing = 15;/** 每个ITEM之间的竖直间距 */private int mVerticalSpacing = 15;/** item高 */private int itemHeight;/** item宽 */private int itemWidth;/** 屏幕上的X */private int win_view_x;/** 屏幕上的Y*/private int win_view_y;/** window属性*/private WindowManager.LayoutParams windowParams = null;/** WindowManager管理器 */private WindowManager windowManager = null;/** 拖动的时候放大的倍数 */private double dragScale = 1.2D;/** 拖动的时候对应ITEM的VIEW */private View dragImageView = null;/** 点击时候的X位置 */public int downX;/** 点击时候的Y位置 */public int downY;/** 点击时候对应整个界面的X位置 */public int windowX;/** 点击时候对应整个界面的Y位置 */public int windowY;/** 一行的ITEM数量*/private int nColumns = 4;/* 移动时候最后个动画的ID */private String LastAnimationID;//长按开始位置(第一次)private int startPosition;//长按的位置private int dragPosition;//是否移动private boolean isMove = false;//移动的次数private int moveNum = 0;public DragGrid(Context context) {super(context);init(context);}public DragGrid(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(context);}public DragGrid(Context context, AttributeSet attrs) {super(context, attrs);init(context);}/** 在ScrollView内,所以要进行计算高度 */@Overridepublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);super.onMeasure(widthMeasureSpec, expandSpec);}private void init(Context context){//将布局文件中设置的间距dip转为pxmHorizontalSpacing = DataTools.dip2px(context, mHorizontalSpacing);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubif (ev.getAction() == MotionEvent.ACTION_DOWN) {windowX = (int) ev.getX();windowY = (int) ev.getY();setOnItemClickListener(ev);}return super.onInterceptTouchEvent(ev);}/*有一种方法可以阻止父层的View截获touch事件,就是调用getParent().requestDisallowInterceptTouchEvent(true);方法。一旦底层View收到touch的action后调用这个方法那么父层View就不会再调用onInterceptTouchEvent了,也无法截获以后的action。*//** requestDisallowInterceptTouchEvent():这个方法就是告诉父层不需要调用onInterceptTouchEvent()方法* * 在响应touch事件时,会先调用父控件onInterceptTouchEvent()方法,然后在往下传递* 详细请看博客*/@Overridepublic boolean onTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubint x = (int) ev.getX();int y = (int) ev.getY();if (dragImageView != null&& dragPosition != AdapterView.INVALID_POSITION) {int action = ev.getAction();switch (action) {case MotionEvent.ACTION_DOWN:windowX = (int) ev.getX();windowY = (int) ev.getY();break;case MotionEvent.ACTION_MOVE:onDrag((int) ev.getRawX(), (int) ev.getRawY());if(!isMove){onMove(x, y);}break;case MotionEvent.ACTION_UP:stopDrag();onDrop(x, y);requestDisallowInterceptTouchEvent(false);break;default:break;}}return super.onTouchEvent(ev);}/* 显示拖动之后位置上的内容 */private void onDrop(int x, int y){DragGridAdapter mDragGridAdapter = (DragGridAdapter) getAdapter();mDragGridAdapter.setShowDropItem(true);mDragGridAdapter.notifyDataSetChanged();}/* 窗口跟随手指进行移动 */private void onDrag(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);}}private void setOnItemClickListener(final MotionEvent ev){setOnItemLongClickListener(new OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {// TODO Auto-generated method stubstartPosition = position;dragPosition = position;if(startPosition <= 1){return false;}//getChildAt() 获取的是Grid 中的itemViewGroup dragViewGroup = (ViewGroup) getChildAt(position);TextView dragTextView = (TextView) dragViewGroup.findViewById(R.id.text_item);//setSelected:改变视图的选中状态。视图有选中和未选中两个状态。注意,选择状态不同于焦点。 //典型的选中的视图是象 ListView 和 GridView 这样的 AdapterView 中显示的 内容;选中的内容会显示为高亮dragTextView.setSelected(true);dragTextView.setEnabled(false);itemHeight = dragViewGroup.getHeight();itemWidth = dragViewGroup.getWidth();//               System.out.println("dragViewGroup.getHeight()->" + dragViewGroup.getHeight());
//              System.out.println("dragViewGroup.getWidth()->" + dragViewGroup.getWidth());
//              System.out.println("dragTextView.getHeight()->" + dragTextView.getHeight());
//              System.out.println("dragTextView.getWidth()->" + dragTextView.getWidth());if(dragPosition != AdapterView.INVALID_POSITION){//现在获取的ev.getX,ev.getY 与 windowX 、windowY 怎么会不一样那 尤其是Y坐标会差距那么大//getLeft, getRight, getTop, getBottom是相对其父视图的位置/*event.getRowX():触摸点相对于屏幕原点的x坐标*event.getX():   触摸点相对于其所在组件原点的x坐标*/win_view_x = windowX - dragViewGroup.getLeft();win_view_y = windowY - dragViewGroup.getTop();/** 在Android中自有获取view中的cache内容,然后将内容转换成bitmap,方法名是:getDrawingCache(),返回结果为Bitmap* destroyDrawingCache():用来销毁旧的cache* setDrawingCacheEnabled():用来把cache开启,不然没有办法获取cache* getDrawingCache():用来获取view中的cache内容,并把获取的内容转换成Bitmap*/dragViewGroup.destroyDrawingCache();dragViewGroup.setDrawingCacheEnabled(true);Bitmap dragBitmap = Bitmap.createBitmap(dragViewGroup.getDrawingCache());dragViewGroup.setDrawingCacheEnabled(false);startDrag(dragBitmap, (int)ev.getRawX(),  (int)ev.getRawY());hideDropItem();
//                  dragViewGroup.setVisibility(View.INVISIBLE);dragTextView.setBackgroundResource(R.drawable.diji2);dragTextView.setText("");isMove = false;//阻止父层的View截获touch事件requestDisallowInterceptTouchEvent(true);return true;}return false;}});}/** 隐藏 放下 的ITEM*/private void hideDropItem() {((DragGridAdapter) getAdapter()).setShowDropItem(false);}//创建悬浮窗口private void startDrag(Bitmap bitmap, int rawX, int rawY){stopDrag();windowParams = new WindowManager.LayoutParams();windowParams.gravity = Gravity.TOP | Gravity.LEFT;/** windowParams.x* 如果忽略gravity属性,那么它表示窗口的绝对X位置。* 什么是gravity属性呢?简单地说,就是窗口如何停靠。* 当设置了 Gravity.LEFT 或 Gravity.RIGHT 之后,x值就表示到特定边的距离。*/windowParams.x = rawX - win_view_x;/** windowParams.y* 如果忽略gravity属性,那么它表示窗口的绝对Y位置。* 当设置了Gravity.TOP 或 Gravity.BOTTOM 之后,y值就表示到特定边的距离。*/windowParams.y = rawY - win_view_y;windowParams.width = (int) (dragScale * bitmap.getWidth());windowParams.height = (int) (dragScale * bitmap.getHeight());/** FLAG_NOT_FOCUSABLE:不能获得按键输入焦点,所以不能向它发送按键或按钮事件* FLAG_NOT_TOUCHABLE:不接受触摸屏事件。* FLAG_KEEP_SCREEN_ON: 当此窗口为用户可见时,保持设备常开,并保持亮度不变* FLAG_LAYOUT_IN_SCREEN:窗口占满整个屏幕,忽略周围的装饰边框(例如状态栏)。此窗口需考虑到装饰边框的内容*/this.windowParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
//      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;//期望的位图格式。默认为不透明.参考android.graphics.PixelFormat。//还不是很清楚windowParams.format = PixelFormat.TRANSLUCENT;//窗口所使用的动画设置。它必须是一个系统资源而不是应用程序资源,因为窗口管理器不能访问应用程序。// windowParams.windowAnimations = 0;ImageView iv = new ImageView(getContext());iv.setImageBitmap(bitmap);windowManager = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);windowManager.addView(iv, windowParams);/* WindowManager是Android中一个重要的服务(Service )。WindowManager Service 是全局的,是唯一的。* 它将用户的操作,翻译成为指令,发送给呈现在界面上的各个Window。Activity会将顶级的控件注册到 Window Manager 中,* 当用户真是触碰屏幕或键盘的时候,Window Manager就会通知到,而当控件有一些请求产生,也会经由ViewParent送回到Window Manager中。* 从而完成整个通信流程。整个Android的窗口机制是基于一个叫做 WindowManager,这个接口可以添加view到屏幕,也可以从屏幕删除view。* 它面向的对象一端是屏幕,另一端就是View,通过WindowManager的 addView方法创建View,这样产生出来的View根据* WindowManager.LayoutParams属性不同,效果也就不同了。比如创建 系统顶级窗口,实现悬浮窗口效果!* WindowManager的方法很简单,基本用到的就三addView,removeView,updateViewLayout。接口,* 而WindowManager.LayoutParams的属性就多了,非常丰富,具体请查后面介绍*/dragImageView = iv;}//删除多余窗口private void stopDrag(){if(dragImageView != null){windowManager.removeView(dragImageView);dragImageView = null;}}//得到动画private Animation getMoveAnimation(float x, float y){//Animation.RELATIVE_TO_SELF:相对自己的百分比//view.width * (百分比 + 1)//view.height * (百分比 + 1)TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0F,Animation.RELATIVE_TO_SELF,x, Animation.RELATIVE_TO_SELF, 0.0F,Animation.RELATIVE_TO_SELF, y);// 当前位置移动到指定位置//请看博客// translateAnimation.setFillAfter(true);//延迟/** public void setDuration (long durationMillis)* 参数durationMillis为动画的持续时间,单位为毫秒(ms)*/translateAnimation.setDuration(300L);return translateAnimation;}private void onMove(int x, int y){final int belowPosition = pointToPosition(x, y);if(belowPosition <= 1){return;}if(belowPosition == -1 || belowPosition == startPosition){return;}if(dragPosition != startPosition){dragPosition = startPosition;}moveNum = belowPosition - dragPosition;if(moveNum == 0){return;}ViewGroup group = (ViewGroup) getChildAt(dragPosition);group.setVisibility(View.INVISIBLE);float to_x = 1;// 当前下方positonfloat to_y;// 当前下方右边positon//没有理解//x_vlaue移动的距离百分比(相对于自己长度的百分比)float x_value = ((float) mHorizontalSpacing / (float) itemWidth) + 1.0f;//y_vlaue移动的距离百分比(相对于自己宽度的百分比)float y_value = ((float) mVerticalSpacing / (float) itemHeight) + 1.0f;int length = Math.abs(moveNum);int holdPosition;for(int i = 0;i < length;i ++){if(moveNum > 0){holdPosition = dragPosition + i + 1;if(holdPosition/nColumns == dragPosition/nColumns){to_x = -x_value;to_y = 0;}else if(holdPosition % 4 == 0){to_x = 3 * x_value;to_y = -y_value;}else{to_x = -x_value;to_y = 0;}} else{holdPosition = dragPosition  - i - 1;if(holdPosition/nColumns == dragPosition/nColumns){to_x = x_value;to_y = 0;}else if(holdPosition % 4 == 3){to_x = - 3 * x_value;to_y = y_value;}else{to_x = x_value;to_y = 0;}}ViewGroup moveViewGroup = (ViewGroup)getChildAt(holdPosition);Animation moveAnimation = getMoveAnimation(to_x, to_y);moveViewGroup.startAnimation(moveAnimation);if (holdPosition == belowPosition) {LastAnimationID = moveAnimation.toString();}moveAnimation.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {// TODO Auto-generated method stubisMove = true;}@Overridepublic void onAnimationRepeat(Animation animation) {// TODO Auto-generated method stub}@Overridepublic void onAnimationEnd(Animation animation) {// TODO Auto-generated method stubif (animation.toString().equalsIgnoreCase(LastAnimationID)) {DragGridAdapter mDragAdapter = (DragGridAdapter) getAdapter();mDragAdapter.exchange(startPosition,belowPosition);startPosition = belowPosition;dragPosition = belowPosition;isMove = false;}}});}}}

代码下载:点击下载

今日头条 频道管理(删除、添加、拖动)相关推荐

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

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

  2. 使用 draggrid 实现 仿今日头条频道管理(详细步骤)

    Android 中   使用 draggrid 实现仿今日头条频道管理(详细步骤) 前言 最近开发的项目中有类似今日头条新闻的频道管理,用的是第三方的draggrid  所以试着尝试做了一下.代码如下 ...

  3. 今日头条频道管理(自带动画效果)

    1. 在新的Module 里面 build.gradle进行添加 compile 'com.github.andyoom:draggrid:v1.0.1' 2.在项目里build.gradle中添加 ...

  4. Android仿头条频道管理

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

  5. 腾讯再诉今日头条系 要求删除用户游戏视频

    据悉,腾讯在南山法院对今日头条和抖音又新增6起诉讼,要求删除两个平台6个用户所发布的所有<王者荣耀>游戏视频,并赔偿经济损失合计1076万. 腾讯分别在6起案件中主张,今日头条未经授权传播 ...

  6. android的今日头条软件怎么删除,如何把今日头条账号注销 退出账号的方法教程[多图]...

    今日头条这个软件受到很多朋友用户的喜爱,对于在使用这个软件的时候朋友用户都会先登录账号,但当想要注销账号了怎么办?如何把今日头条账号注销?废话不多说,下面apk3来帮助大家解决今日头条退出账号的方法教 ...

  7. Android 频道管理,可拖动item排列,删除,添加

    样式效果           1.创建自定义GridView /*** 作者:created by meixi* 邮箱:15913707499@163.com* 日期:2019/5/31 13*/pu ...

  8. android 横向滚动 导航,仿今日头条横向滚动导航栏--原生js

    咳咳!先打一波小广告,在上一篇里忘记了,那啥--我的那个个人博客做好了-->(我的博客) 好嘞,言归正传,说说我们的效果. 其实就是实现横向滑动,进行选择. 原理: 鼠标按下,获取当前鼠标坐标, ...

  9. 仿今日头条后台管理系统(一)

    (一)今日头条后台管理项目 01-项目-简单介绍 ​ (理解今日头条)的后台管理系统,个人的后台管理系统,发布文章新闻不便利,需要这个PC的系统. 登录 欢迎页面 发布文章 素材管理 内容管理 粉丝管 ...

最新文章

  1. [PHP]php基础练习题学习随笔
  2. 页面的前进/后退/刷新方法
  3. 第三次学JAVA再学不好就吃翔(part19)--二维数组
  4. nginx配置静态文件过期时间
  5. c#对数据库访问完应关闭连接
  6. java常见面试题——java常见笔试题
  7. WebAPI和Node
  8. 手把手教你如何利用Kickstart自动安装虚拟机
  9. pytorch学习笔记(二十三):卷积神经网络(LeNet)
  10. 华为云郑叶来:优势挡不住趋势,技术创新是主旋律
  11. 手机平板巡检系统,掀起设备巡检的第2次革命
  12. 线程停止继续_Java并发学习第二弹:如何正确停止线程?
  13. ubuntu修改文件权限
  14. (转) oracle清空数据库脚本
  15. linux授读写权限,Linux系统中,设定资料读写权限
  16. excel高级筛选怎么用_Excel工作表中如何使用高级筛功能来实现多条件筛选
  17. 扫地机器人自动回充原理
  18. 无线设置时服务器无响应怎么办,无线路由器怎么设置服务器未响应
  19. 构建“未来级”企业,如何做对这道必答题
  20. 进入bios或者安全模式

热门文章

  1. APP设计师拿到APP产品原型开始,七步搞定APP设计
  2. React版本18.xx降低为17.xx
  3. 算法导论 — 8.1 排序算法的下界
  4. 使用第三方jieba中文分词库对三国演义片段进行分词统计
  5. ADU87、DCB20X-E等设备以RTSP方式添加第三方相机或录像机教程
  6. NYOJ101两点距离
  7. 二样本感知器的matlab程序设计
  8. 拿到Google offer了
  9. 通达OA-进销存系统
  10. Numba编译器的介绍与应用