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画图,删除图标后应该重新排布热座上的图标。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值