本文主要是介绍自定义ViewGroup之仿网易新闻栏目管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
之前一直想写个,但是没时间。现在补上。先上效果图:
先分析一下,想到的两种实现方法:
第一种:
1. 当用户长按选择一个item时,将该item隐藏,然后用WindowManager添加一个新的window,该window与所选择item一模一样,并且跟随用户手指滑动而不断改变位置。
2. 当window的位置坐标在GridView里面时,使用pointToPosition (int x, int y)方法来判断对应的应该是哪个item,在adapter中作出数据集相应的变化,然后做出平移的动画。
3. 当用户手指抬起时,把window移除,使用notifyDataSetChanged()做出GridView更新
第二种:
用getView获取要拖动的view,在Move事件下不断平移得到x新的坐标调用onLayout(true,l,t,r,b);
view.startAnimation; onLayout(true, getLeft(), getTop(), getRight(), getBottom());
1. 当用户长按选择一个item时,将该item隐藏,然后用WindowManager添加一个新的window,该window与所选择item一模一样,并且跟随用户手指滑动而不断改变位置。
2. 当window的位置坐标在GridView里面时,使用pointToPosition (int x, int y)方法来判断对应的应该是哪个item,在adapter中作出数据集相应的变化,然后做出平移的动画。
3. 当用户手指抬起时,把window移除,使用notifyDataSetChanged()做出GridView更新
第二种:
用getView获取要拖动的view,在Move事件下不断平移得到x新的坐标调用onLayout(true,l,t,r,b);
view.startAnimation; onLayout(true, getLeft(), getTop(), getRight(), getBottom());
第一种看到已经有人实现了,但是偶尔会有崩溃的问题。于是我根据他的思路,以自己更容易理解的方式再写了一遍。在此对这位兄弟表示感谢,地址我会贴在文章最后.
第二种有时间再补上。
下面正式开始:
先看一下所有的方法:
DragGridView继承GridView,在onInterceptTouchEvent的ACTION_DOWN时设置长按监听。长按item触发OnItemLongClickListener,
在这里windowManager.addView(dragView, windowLayoutParams);
onTouchEvent方法判断更新操作:
@Override public boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:lastX = (int) ev.getRawX(); lastY = (int) ev.getRawY(); windowX = (int) ev.getX(); windowY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE://拖动时判断位置,平移; if (isDraging) {updateWindow(ev, (int) ev.getRawX() - lastX, (int) ev.getRawY() - lastY); lastX = (int) ev.getRawX(); lastY = (int) ev.getRawY(); }break; case MotionEvent.ACTION_UP://拖动时判断位置,平移; if (isDraging) {isDraging = false; closeWindow(ev); }break; }return super.onTouchEvent(ev); }
重要的方法:
updateWindow();
/** * 更新悬浮窗位置; * * @param ev */ private void updateWindow(MotionEvent ev, int deltaX, int deltaY) {mTempPos = pointToPosition((int) ev.getX(), (int) ev.getY()); if (mTempPos != AdapterView.INVALID_POSITION && mTempPos != prePos) {if (mTempPos > prePos) {for (int i = prePos + 1; i <= mTempPos; i++) {Animation moveAnimation; if (i % numColumns == 0) {moveAnimation = getMoveAnimation((numColumns - 1) * horizon_div, -vertical_div); } else {moveAnimation = getMoveAnimation(-horizon_div, 0); }getChildAt(i).startAnimation(moveAnimation);//left. if (i == mTempPos) {lastAniID = moveAnimation.toString(); }moveAnimation.setAnimationListener(new Animation.AnimationListener() {@Override public void onAnimationStart(Animation animation) {isMoving = true; }@Override public void onAnimationEnd(Animation animation) {swap(animation); isMoving = false; }@Override public void onAnimationRepeat(Animation animation) {}}); }} else {//mTempPos < prePos for (int i = prePos - 1; i >= mTempPos; i--) {Animation moveAnimation; if (i % numColumns == numColumns - 1) {moveAnimation = getMoveAnimation(-(numColumns - 1) * horizon_div, vertical_div); } else {moveAnimation = getMoveAnimation(horizon_div, 0); }getChildAt(i).startAnimation(moveAnimation);//left. if (i == mTempPos) {lastAniID = moveAnimation.toString(); }moveAnimation.setAnimationListener(new Animation.AnimationListener() {@Override public void onAnimationStart(Animation animation) {}@Override public void onAnimationEnd(Animation animation) {swap(animation); }@Override public void onAnimationRepeat(Animation animation) {}}); }}((DragAdapter) getAdapter()).swap(prePos, mTempPos); prePos = mTempPos; }windowLayoutParams.x += deltaX; windowLayoutParams.y += deltaY; windowManager.updateViewLayout(dragView, windowLayoutParams); }prePos为上一次拖动的位置,mTempPos为当前window添加的dragView移到的位置,不相等时出发平移动画,并且置换数据位置。
最后在UP事件时调用closeWindow,移除windowManager的view,显示之前隐藏的item。移除子view的动画。
这么思路整理下来,还是挺简单的,实际写的时候还是有需要注意的点:
1.在子view结束动画后,需要 clearAnimation(),因为Animation.setFillAfter(true);执行动画后,数据有变动了 ,再notify时也不会消除上一次动画的影响,造成错位。
2. 刚开始我使用的是动画结束才真实交换数据位置。但这样但会造成两次动画,因为动画没结束,prePos和mTempPos没变化,会再次触发动画。解决方法就是触发动画的同时真实交换数据位置。
3.在windowmanager添加view时:app主题为actionbar时会偏移,<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">改为NoActionBar。windowLayoutParams.y = DragGridView.this.getTop() + view.getTop();(这个是之前的写法,不适用于在scrollView的情况)
3.需要在scrollView中使用该控件,需要解决显示的长度,和事件冲突。(具体看源码,这里不在解释)
最后附上源码地址:https://github.com/Ulez/WangyiIndicator
参考:http://www.jianshu.com/p/559b631ec330
这篇关于自定义ViewGroup之仿网易新闻栏目管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!