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

来源:互联网 发布:xp动态壁纸软件 编辑:程序博客网 时间:2024/05/17 01:05

频道管理共分为两部分:


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


一、频道的删除和添加


利用监听来进行动画的执行。
动画:以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 stub    int[] 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;}}});}}}


代码下载:点击下载


0 0
原创粉丝点击