Launcher3 长按Hotseat图标,显示删除角标(红底白杠杠用于删除图标或者显示应用未读消息数量)

news2024/9/24 17:17:33

基于Android 13,Launcher3实现需求:

1. 长按Hotseat的图标显示红色删除角标

2. 点击角标,删除图标并保存到Database

3.点击其他地方,取消编辑hotseat图标模式

实现效果:

实现原理:

 

图标是由BubbleTextView来是实现的,是一个TextView,要增加角标应该有几种思路:

1.TextView可以设置 left top bottom right 4个drawable,top已经用作实际的icon,这个应该布局不了

2. 修改背景background,在适当的时候修改background?

3.重写TextView的onDraw,适当的时候在原来的基础上画出额外的角标

查看Android13原生的Launcher代码发现 BubbleTextView的onDraw已经有DotRenderer的实现,显示的应该是应用通知,因此模仿这个实现思路即可。

查看源码发现实际使用的是DoubleShadowBubbleTextView.java,调用到的是ondraw调用的是drawWithoutDot

因此在BubbleTextView.java中添加代码即可实现:

 

protected void drawWithoutDot(Canvas canvas) {
        super.onDraw(canvas);
        drawMyDotIfNecessary(canvas);
}

protected void drawMyDotIfNecessary(Canvas canvas){
        if(!mIsDeleteHidden) {
            Paint paint = new Paint();
            paint.setColor(Color.RED); // 角标颜色
            paint.setStyle(Paint.Style.FILL);
            canvas.drawCircle(getWidth() - 30f, 30f, 30f, paint);
        }
}

 

接下来应该需要实现在什么时候显示圆点操作,

比方说长按某一个hotseat里图标,则所有的view都添加这个圆点

长按图标事件可以得到,在什么时候取消呢?点击图标非圆点处取消。

接下来实现,点击圆点事件:把点击事件传到mHotseatController里删除并更新hotseat里的view

 step1: 在BubbleTextView.java里实现onDraw画图,捕捉点击圆点事件,实现显示隐藏角标接口

private boolean mIsDeleteHidden = true;//Kevin.Ye added
private boolean mIsDownInDotErea = false;//
private Rect mRectDotBounds = null;//
private OnDotClkListener mOnDotClkListener = null;
//Kevin.Ye added end

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // ignore events if they happen in padding area
        if(cancelDotIfNecessary(event))//added by Kevin.Ye case when Dot is shown
            return true;//end

        if (event.getAction() == MotionEvent.ACTION_DOWN
                && shouldIgnoreTouchDown(event.getX(), event.getY())) {
            return false;
        }

        if (isLongClickable()) {
            super.onTouchEvent(event);
            mLongPressHelper.onTouchEvent(event);
            // Keep receiving the rest of the events
            return true;
        } else {
            return super.onTouchEvent(event);
        }
    }
private boolean cancelDotIfNecessary(MotionEvent event){
       if(isMyDotHidden())
           return false;
       switch (event.getAction()){
         case MotionEvent.ACTION_DOWN:
            if(isTouchInDotErea((int)event.getX(),(int)event.getY())) {
                mIsDownInDotErea = true;
                return true;
            }
            break;
          case MotionEvent.ACTION_UP:
            if(mIsDownInDotErea){
                mIsDownInDotErea = false;
                if(isTouchInDotErea((int)event.getX(),(int)event.getY())){
                    onClkMyDot();
                    return true;
                }else{
                    Log.d("dot","touch up elsewhere");
                }
            }
            break;
       }
       return false;
    }
    private boolean isTouchInDotErea(int x,int y){
        Log.d("dot","touch x:"+x+" y:"+y);
        if(mRectDotBounds == null) {
             mRectDotBounds = new Rect(getWidth() - 60, 0, getWidth(), 60);
        }
        return mRectDotBounds.contains(x,y);
    }
    private void onClkMyDot(){
        Log.d("dot","onClkMyDot");
        if(mOnDotClkListener != null)
            mOnDotClkListener.onClkIconDot(BubbleTextView.this);
    }

    public interface OnDotClkListener{
        void onClkIconDot(View view);
    }
    public void setOnDotClkListener(OnDotClkListener onDotClkListener){
        mOnDotClkListener = onDotClkListener;
    }
/*
     *draw my dot for deleting or added icon Kevin.Ye
    */
    private boolean isMyDotHidden(){
        return mIsDeleteHidden;
    }
    public void setDeleteDotHidden(boolean hide){
        mIsDeleteHidden = hide;
        invalidate();
    }
    protected void drawMyDotIfNecessary(Canvas canvas){
        if(!mIsDeleteHidden) {
           Paint paint = new Paint();
           paint.setColor(Color.RED); // 角标颜色        paint.setStyle(Paint.Style.FILL);
           canvas.drawCircle(getWidth() - 30f, 30f, 30f, paint);
        }
    }

 

step2: HotseatController.java(注意本类是源码没有的),实现显示角标、取消显示角标、响应删除图标三个接口

private boolean mIsInDeletingMode = false;
    public boolean isInDeletingMode(){
        return mIsInDeletingMode;
    }
    public void showHotseatDeleteDot(){
        mIsInDeletingMode = true;
        Hotseat hs = mLauncher.getHotseat();
        int gridCount = getGridCount(mLauncher);
        //ArrayList<View> views = new ArrayList<>();
        for (int i = 0; i < gridCount; i++) {
            int cx = hs.getCellXFromOrder(i);
            int cy = hs.getCellYFromOrder(i);
            View v = hs.getShortcutsAndWidgets().getChildAt(cx, cy);
            if (hs.isOccupied(cx, cy)) {
                if (v != null) {
                    if(v instanceof BubbleTextView){
                        Log.d("dot","v instanceof BubbleTextView!!!");
                        ((BubbleTextView)v).setDeleteDotHidden(false);
                        ((BubbleTextView)v).setOnDotClkListener(mOnDotClkListener);
                    }
                }
            }
        }
    }
    public void cancelDeletingMode(){
        mIsInDeletingMode = false;
        Hotseat hs = mLauncher.getHotseat();
        int gridCount = getGridCount(mLauncher);
        //ArrayList<View> views = new ArrayList<>();
        for (int i = 0; i < gridCount; i++) {
            int cx = hs.getCellXFromOrder(i);
            int cy = hs.getCellYFromOrder(i);
            View v = hs.getShortcutsAndWidgets().getChildAt(cx, cy);
            if (hs.isOccupied(cx, cy)) {
                if (v != null) {
                    if(v instanceof BubbleTextView){
                        Log.d("dot","v instanceof BubbleTextView!!!");
                        ((BubbleTextView)v).setDeleteDotHidden(true);
                    }
                }
            }
        }
    }

    BubbleTextView.OnDotClkListener mOnDotClkListener = new BubbleTextView.OnDotClkListener() {
        @Override
        public void onClkIconDot(View view) {
            Log.d("dot","HotseatController onClkMyDot");
            Hotseat hs = mLauncher.getHotseat();
            hs.removeView(view);
            //Log.d("dot","view.getTag() :"+view.getTag().toString());
            Object tag = view.getTag();
            WorkspaceItemInfo info = tag instanceof WorkspaceItemInfo ? (WorkspaceItemInfo) tag : null;
            if(info != null) {
                mLauncher.getModelWriter().deleteItemFromDatabase(info,null);
            }
        }
    };

step3:Launcher.java中增加调用取消编辑hotseat模式(隐藏角标)

private HotseatController mHotseatController = null;//Kevin.Ye
 
mHotseatController = new HotseatController(this.getApplicationContext(),this);//Kevin.Ye

 /**
     *Return HotseatController Kevin.Ye added
     */
public HotseatController getHotseatController(){
   	return mHotseatController;
}

@Override
 public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
        /*Kevin.Ye added for cancel deleting mode*/
        if(getHotseatController().isInDeletingMode()){
            getHotseatController().cancelDeletingMode();
            return true;
        }


}




step4:src/com/android/launcher3/Workspace.java 中的接口DragView beginDragShared

实现长按进入Hotseat图标编辑模式(显示删除角标)

        if (child.getParent() instanceof ShortcutAndWidgetContainer) {
            mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent();
        }

        if (child instanceof BubbleTextView && !dragOptions.isAccessibleDrag) {
           //Kevin.Ye added for showing hotseat edit mode
           boolean bStartLongPressAction = true;
           if(child.getParent() instanceof ShortcutAndWidgetContainer)
              if(child.getParent().getParent() instanceof Hotseat){
                  mLauncher.getHotseatController().showHotseatDeleteDot();
                  bStartLongPressAction = false;
              }
           //add end
           if(bStartLongPressAction)
               dragOptions.preDragCondition = ((BubbleTextView) child).startLongPressAction();
        }

后续应该用加载drawable的方式来代替drawCircle画图,删除图标后应该重新排布热座上的图标。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2084289.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剑侠情缘c#版(游戏源码+资源+工具+程序),百度云盘下载,大小1.68G

剑侠情缘c#版&#xff08;游戏源码资源工具程序&#xff09;&#xff0c;c#开发的&#xff0c;喜欢研究游戏的可以下载看看。亲测可进游戏。 剑侠情缘c#版&#xff08;游戏源码资源工具程序&#xff09;下载地址&#xff1a; 通过网盘分享的文件&#xff1a;【游戏】剑侠情缘c#…

jmeter如何把一个请求的响应中部分字段提取出来便于下个请求用

jmeter如何把一个请求的响应中部分字段提取出来便于下个请求用&#xff0c;可以通过json提取器提取&#xff0c;如果提取多个&#xff0c;就设置多个json提取。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/dd5afb1fca3f4e31b636e17e11e8dfc3.png

2.10鼠标事件

目录 实验原理 实验代码 运行结果 文章参考 实验原理 在 OpenCV 中存在鼠标的操作&#xff0c;比如左键单击、双击等。对于 OpenCV 来讲&#xff0c;用户的鼠标操作被认为发生了一个鼠标事件&#xff0c;需要对这个鼠标事件进行处理&#xff0c;这就是事件的响应。下面我们…

手机ip频繁跳动的原因是什么?手机ip地址老是变怎么解决

在当今数字化时代&#xff0c;‌手机已成为我们生活中不可或缺的一部分。‌然而&#xff0c;‌有些用户可能会遇到手机IP地址频繁变动的问题&#xff0c;‌这不仅可能影响网络连接的稳定性&#xff0c;‌还可能对特定的在线活动造成困扰。‌本文将深入探讨手机IP频繁跳动的原因…

传输大咖36 | 镭速轻松解决医疗卫生行业跨网文件传输难题

在医疗领域&#xff0c;医疗数据的关键性显而易见。病历详尽记载与医学影像数据等&#xff0c;均为确保精确诊断与治疗成效的基石。但是&#xff0c;医疗数据量的迅猛增长使得传统文件传输方法的不足之处日益凸显&#xff0c;难以跟上现代医学的步伐。特别是在跨网文件交换这一…

SSM框架之Mybatis

前言 什么是框架&#xff1f; 框架就是对技术的封装&#xff0c;将基础的技术进行封装&#xff0c;便于程序员使用&#xff0c;提高开发效率 ssm框架是什么&#xff1f; ssm包括spring、springMvc、Mybatis&#xff0c;是后端企业级开发时会使用到的框架组合&#xff0c;在…

无人机搭载高压喷水清洗绝缘子技术详解

随着电力行业的快速发展&#xff0c;高压输电线路作为电力传输的“大动脉”&#xff0c;其安全稳定运行至关重要。绝缘子作为输电线路中的重要组件&#xff0c;长期暴露于自然环境中&#xff0c;易受尘埃、鸟粪、盐雾等污染物附着&#xff0c;导致绝缘性能下降&#xff0c;甚至…

Visual Basic 6.0教程/Visual Basic从入门到实践/Visual Basic学习视频教程

Visual Basic 6.0教程/Visual Basic从入门到实践/Visual Basic学习视频教程 李天生VB从入门到精通 第一章 VisualBasic6基本介绍 第二章 VisualBasic6的数据类型与运算符表达式 第三章 VisualBasic6的内部函数 第四章 VisualBasic6的基本语句 第五章 VisualBasic6的数组 第六章…

AMC8美国数学竞赛备考:吃透625道真题和知识点(持续)

距离接下来最近的2025年AMC8美国数学竞赛还有几个月的时间&#xff0c;实践证明&#xff0c;做真题&#xff0c;吃透真题和背后的知识点是备考AMC8有效的方法之一。 2000-2024年AMC8真题和解析&#xff1a;2023年第13题 这道题的考点是分数。 题意的重点是均匀分布&#xff0c…

OpenCV绘图函数(5)绘制标记函数drawMarker()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::drawMarker 函数在 OpenCV 中用于在一个给定的位置上绘制标记。目前支持几种不同的标记类型&#xff0c;具体信息可以参考 MarkerTypes 函数…

这样图解Transformer应该没人看不懂了吧——多头注意力机制详解

这是关于Transformer系列文章的第三篇部分&#xff0c;我们将用自上而下的方式深入探讨Transformer的功能。 在前两篇文章中&#xff0c;我们已经了解了Transformer是什么、它的架构以及工作原理。 没看过的同学可以点击图片进行查看 Transformer图解1—基础与架构 Transform…

ITopologicalOperator.Intersect 直接崩软件,也不报错的解决方案

1、问题描述&#xff1a; 说多崩溃就有多崩溃&#xff0c;执行到下面这个相交分析的时候&#xff0c;就一直崩软件&#xff0c;用catch也catch不到东西&#xff0c;相同的数据放到另外一个工程中的时候&#xff0c;又是正常的&#xff0c;一直找不到原因。 2、终级方案 最终…

LLM - 自定义图像数据集 使用 LoRA 微调 图像生成 Flux 模型

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/141638928 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 在 Dif…

假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(注意不设头指针),试编写相应的置空队列、判断队列是否为空、入队和出队等算法。

typedef int Datatype; typedef struct queue {Datatype data;struct queue* next; }queue; //队列 typedef struct {queue* rear; }LinkQueue; //初始化 void queueinit(LinkQueue* ps) {ps->rear (queue*)malloc(sizeof(queue));if (ps->rear NULL){perror("err…

家里养宠物空气净化器有用吗,应该怎么挑选宠物空气净化器

养猫&#xff0c;无疑给了我们很多陪伴和乐趣&#xff0c;为我们的生活添上了无数温馨的色彩。然而&#xff0c;在这份甜蜜的负担中&#xff0c;猫毛的问题确实成为了不少铲屎官们共同的“小烦恼”。这些浮毛总能在你最不经意的时候&#xff0c;悄悄占领家中的每一个角落。每天…

不仅仅是文化:解决常见安全问题根源

今年&#xff0c;GitLab对DevSecOps专业人士的年度调查发现了一些与组织文化相关的问题&#xff0c;这些问题可能会阻碍工程团队和安全团队之间的更深层次协调。 大多数(58%)的安全受访者表示&#xff0c;他们很难让开发部门优先修复漏洞&#xff0c;52%的人表示&#xff0c;繁…

Getting AttributeError when using openAI python library

题意&#xff1a;“使用 OpenAI Python 库时出现 AttributeError” 问题背景&#xff1a; Im building a new AI chatbot utilizing the openai library and I have a gradio UI set up in one file (app.py) and a predict() function in another (trainedBot.py) Every time…

【Threejs学习】材质灯光投影

一、光源分类 环境光(AmbientLight)&#xff1a;会均匀的照亮场景中的所有物体。无方向&#xff0c;不能投射阴影。平行光(DirectionalLight)&#xff1a;沿特定方向散发的光&#xff0c;发出的光线都是平行的。例如太阳光&#xff0c;可投射阴影。点光源(PointLight)&#xf…

2024年大学生适合入手的蓝牙耳机推荐?四款开放式耳机推荐

2024年大学生入手蓝牙耳机的话&#xff0c;我当然是比较推荐入手开放式蓝牙耳机的。 主要是因为开放式蓝牙耳机佩戴起来真的很舒适&#xff0c;它的开放式设计通常是轻巧且适配贴合不同耳型的&#xff0c;所以既不会对耳朵造成压迫感&#xff0c;也适合长时间佩戴使用。 不仅…

华为AC旁挂二层组网配置详解:从DHCP部署到无线业务配置,完成网络搭建

组网需求 AC组网方式&#xff1a;旁挂二层组网。 DHCP部署方式&#xff1a; AC作为DHCP服务器为AP分配IP地址。 防火墙作为DHCP服务器为STA分配IP地址。 业务数据转发方式&#xff1a;直接转发。 网络拓扑图 对于旁边路直接转发&#xff0c;优点就是数据流量不经过AC&…