自定义ViewGroup之仿网易新闻栏目管理

2023-10-23 07:38

本文主要是介绍自定义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());

第一种看到已经有人实现了,但是偶尔会有崩溃的问题。于是我根据他的思路,以自己更容易理解的方式再写了一遍。在此对这位兄弟表示感谢,地址我会贴在文章最后.
第二种有时间再补上。
下面正式开始:
先看一下所有的方法:


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之仿网易新闻栏目管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/266465

相关文章

python uv包管理小结

《pythonuv包管理小结》uv是一个高性能的Python包管理工具,它不仅能够高效地处理包管理和依赖解析,还提供了对Python版本管理的支持,本文主要介绍了pythonuv包管理小结,具有一... 目录安装 uv使用 uv 管理 python 版本安装指定版本的 Python查看已安装的 Python

基于Python和MoviePy实现照片管理和视频合成工具

《基于Python和MoviePy实现照片管理和视频合成工具》在这篇博客中,我们将详细剖析一个基于Python的图形界面应用程序,该程序使用wxPython构建用户界面,并结合MoviePy、Pill... 目录引言项目概述代码结构分析1. 导入和依赖2. 主类:PhotoManager初始化方法:__in

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

基于Spring实现自定义错误信息返回详解

《基于Spring实现自定义错误信息返回详解》这篇文章主要为大家详细介绍了如何基于Spring实现自定义错误信息返回效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景目标实现产出背景Spring 提供了 @RestConChina编程trollerAdvice 用来实现 HTT

nvm如何切换与管理node版本

《nvm如何切换与管理node版本》:本文主要介绍nvm如何切换与管理node版本问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录nvm切换与管理node版本nvm安装nvm常用命令总结nvm切换与管理node版本nvm适用于多项目同时开发,然后项目适配no

SpringSecurity 认证、注销、权限控制功能(注销、记住密码、自定义登入页)

《SpringSecurity认证、注销、权限控制功能(注销、记住密码、自定义登入页)》SpringSecurity是一个强大的Java框架,用于保护应用程序的安全性,它提供了一套全面的安全解决方案... 目录简介认识Spring Security“认证”(Authentication)“授权” (Auth

Redis实现RBAC权限管理

《Redis实现RBAC权限管理》本文主要介绍了Redis实现RBAC权限管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1. 什么是 RBAC?2. 为什么使用 Redis 实现 RBAC?3. 设计 RBAC 数据结构

SpringBoot自定义注解如何解决公共字段填充问题

《SpringBoot自定义注解如何解决公共字段填充问题》本文介绍了在系统开发中,如何使用AOP切面编程实现公共字段自动填充的功能,从而简化代码,通过自定义注解和切面类,可以统一处理创建时间和修改时间... 目录1.1 问题分析1.2 实现思路1.3 代码开发1.3.1 步骤一1.3.2 步骤二1.3.3