当前位置: 首页 > article >正文

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

基于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.kler.cn/a/281536.html

相关文章:

  • 分享一个基于python的内蒙古旅游景点数据分析与采集系统(源码、调试、LW、开题、PPT)
  • Nginx负载均衡中静态与动态内容分离策略与实践
  • 终端防火墙软件功能 | 在终端设备上启用防火墙!终端安全小课堂开讲啦
  • python爬虫:selenium+browsermobproxy实现浏览器请求抓取(模块安装详解)
  • Document TagExplorer:精准标签,快速检索,文档管理新体验
  • Linux之7z命令压缩和解压(三十四)
  • 机器学习之------RNN循环神经网络
  • 笔试训练,牛客.合唱团牛客.kannan与高音牛客.拜访(BFS)牛客.买卖股票的最好时机(四)
  • 如何利用命令模式实现一个手游后端架构?
  • 移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——7.list(模拟实现)
  • jsoncpp 使用说明(ubuntu)
  • 自定义tabbar跳转防止页面抖动(uniapp案例,也适用所有前端项目)
  • 近期29√28 冲击七连红,周五意甲 威尼斯VS都灵 比赛分析 比分预测 免费获取,重榜二串一来了
  • Sui Move HackerHouse@成都圆满落幕,静候下次精彩!
  • 机器学习:集成学习之随机森林
  • 网络安全总结①
  • 【百日算法计划】:每日一题,见证成长(001)
  • 展锐7870 Camera HAL层日志调试
  • MySQL 查询优化详解
  • JAVA如何使用反射突破泛型的限制