自定义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

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

Sentinel 高可用流量管理框架

Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。 Sentinel 具有以下特性: 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应