Android 10.0 Launcher3拖拽图标进入hotseat自适应布局功能实现二

1.前言

在10.0的系统rom定制化开发中,在对于launcher3的一些开发定制中,在对hotseat的一些开发中,需要实现动态hotseat居中
的功能,就是在拖拽图标进入和拖出hotseat,都可以保持hotseat居中的功能,接下来分析下相关功能实现
具体如图:

hotseat


2.Launcher3拖拽图标进入hotseat自适应布局功能实现二的核心类

packages\apps\Launcher3\src\com\android\launcher3\dragndrop\DragDriver.java
packages\apps\Launcher3\src\com\android\launcher3\dragndrop\DragController.java

3.Launcher3拖拽图标进入hotseat自适应布局功能实现二的核心功能分析和实现

Launcher顾名思义,就是桌面的意思,也是android系统启动后第一个启动的应用程序,
:Launcher3负责管理和展示用户手机桌面上的各个应用程序图标。它通过GridView或者LinearLayout等布局管理器将
图标进行排列,并支持滑动、放大缩小等手势操作
在Launcher3中,这些事件通常由DragController类来处理。我们可以在DragController中的onDragStart方法中获取当前屏幕和应用图标数量的信息
DragController:核心拖拽控制器基类,定义很多拖拽相关的公共方法,处理滑动事件等等

3.1 DragController.java中相关拖拽功能分析

在实现Launcher3拖拽图标进入hotseat自适应布局功能实现二的核心功能中,通过上述的分析得知,
DragController.java的相关源码中,它就是核心拖拽控制器基类,处理一下拖拽滑动等事件,Workspace,
Hotseat,Folder等等,拖拽都是在这里控制处理的,接下来看下相关的拖拽接口分析

    public DragView startDrag(Bitmap b, int dragLayerX, int dragLayerY,
            DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion,
            float initialDragViewScale, float dragViewScaleOnDrop, DragOptions options) {
        if (PROFILE_DRAWING_DURING_DRAG) {
            android.os.Debug.startMethodTracing("Launcher");
        }

        // Hide soft keyboard, if visible
        UiThreadHelper.hideKeyboardAsync(mLauncher, mWindowToken);
        AbstractFloatingView.closeOpenViews(mLauncher, false, TYPE_DISCOVERY_BOUNCE);

        mOptions = options;
        if (mOptions.systemDndStartPoint != null) {
            mMotionDownX = mOptions.systemDndStartPoint.x;
            mMotionDownY = mOptions.systemDndStartPoint.y;
        }

        final int registrationX = mMotionDownX - dragLayerX;
        final int registrationY = mMotionDownY - dragLayerY;

        final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
        final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;

        mLastDropTarget = null;

        mDragObject = new DropTarget.DragObject();

        mIsInPreDrag = mOptions.preDragCondition != null
                && !mOptions.preDragCondition.shouldStartDrag(0);

        final Resources res = mLauncher.getResources();
        final float scaleDps = mIsInPreDrag
                ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
        final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
                registrationY, initialDragViewScale, dragViewScaleOnDrop, scaleDps);
        dragView.setItemInfo(dragInfo);
        mDragObject.dragComplete = false;
        if (mOptions.isAccessibleDrag) {
            // For an accessible drag, we assume the view is being dragged from the center.
            mDragObject.xOffset = b.getWidth() / 2;
            mDragObject.yOffset = b.getHeight() / 2;
            mDragObject.accessibleDrag = true;
        } else {
            mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
            mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
            mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);

            mDragDriver = DragDriver.create(mLauncher, this, mDragObject, mOptions);
//add core start
mDragDriver.setLauncher(mLauncher);
//add core end
        }

        mDragObject.dragSource = source;
        mDragObject.dragInfo = dragInfo;
        mDragObject.originalDragInfo = new ItemInfo();
        mDragObject.originalDragInfo.copyFrom(dragInfo);

        if (dragOffset != null) {
            dragView.setDragVisualizeOffset(new Point(dragOffset));
        }
        if (dragRegion != null) {
            dragView.setDragRegion(new Rect(dragRegion));
        }

        mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        dragView.show(mMotionDownX, mMotionDownY);
        mDistanceSinceScroll = 0;

        if (!mIsInPreDrag) {
            callOnDragStart();
        } else if (mOptions.preDragCondition != null) {
            mOptions.preDragCondition.onPreDragStart(mDragObject);
        }

        mLastTouch[0] = mMotionDownX;
        mLastTouch[1] = mMotionDownY;
        handleMoveEvent(mMotionDownX, mMotionDownY);
        mLauncher.getUserEventDispatcher().resetActionDurationMillis();
        return dragView;
    }

在实现Launcher3拖拽图标进入hotseat自适应布局功能实现二的核心功能中,通过上述的分析得知,
DragController.java的相关源码中,当开始拖拽的时候就调用startDrag(Bitmap b, int dragLayerX, int dragLayerY,
            DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion,
            float initialDragViewScale, float dragViewScaleOnDrop, DragOptions options)
来传入拖拽图标的相关参数,拖拽流程就从这里开始,而DragController.java实现了DragDriver.EventListener,
所以具体的OnTouch事件是在DragDriver中处理的,所以就调用DragDriver.create实例化这个实例,
在这里需要用到launcher类,所以添加setLauncher来传递参数
接下来看下DragDriver的相关拖拽处理功能

3.2 DragDriver的相关拖拽处理流程

在实现Launcher3拖拽图标进入hotseat自适应布局功能实现二的核心功能中,通过上述的分析得知,在DragDriver.java的核心功能,就是处理响应拖拽事件,接下来看下onTouchEvent()中处理
拖拽开始和结束的相关功能处理

   public static DragDriver create(Context context, DragController dragController,
            DragObject dragObject, DragOptions options) {
        if (options.systemDndStartPoint != null) {
            return new SystemDragDriver(dragController, context, dragObject);
        } else {
            return new InternalDragDriver(dragController);
        }
    }
class InternalDragDriver extends DragDriver {
    InternalDragDriver(DragController dragController) {
        super(dragController);
    }
//add core start
        @Override
        public boolean onTouchEvent(MotionEvent ev) {

              final int action = ev.getAction();
            switch (action) {
                case MotionEvent.ACTION_MOVE:
                    break;
                case MotionEvent.ACTION_UP:
	    resetLayout();
                    break;
                case MotionEvent.ACTION_CANCEL:
                    break;
            }

            return true;
        }
//add core end
    @Override
    public boolean onDragEvent (DragEvent event) { 

       return false; 
    }
}

//add core start
import android.view.View;
import com.android.launcher3.CellLayout;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Launcher;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Hotseat;
import android.widget.FrameLayout;
import android.content.res.Configuration;
import android.util.DisplayMetrics;
import com.android.launcher3.R;
import android.graphics.Rect;
import com.android.launcher3.DeviceProfile;
import android.view.Gravity;

    public int dip2px(float dpValue) {
		final float scale = mLauncher.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}
	private Launcher mLauncher;
	public void setLauncher(Launcher luncher){
		mLauncher = luncher;
	}
  public void resetLayout() {
    Hotseat mHotSeat = mLauncher.getHotseat();
    ShortcutAndWidgetContainer mContainer = mHotSeat.getShortcutsAndWidgets();
    DisplayMetrics mDisplayMetrics = new DisplayMetrics();
    mLauncher.getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);

    int mMargins;
    int curIconPos=0,hotseatWidth=0;     // 当前 Icon 位置
    int hotseatLength;  // Hotseat 长度
    int maxHotseatIconNum = mLauncher.getDeviceProfile().inv.numHotseatIcons;	// Hotseat Icon 最大个数
    int curOrientation = mLauncher.getResources().getConfiguration().orientation;
    boolean isOrientationPortrait = curOrientation == Configuration.ORIENTATION_PORTRAIT;
    int childcount = mContainer.getChildCount();
	android.util.Log.e("Hotseat","childcount:"+childcount);
        hotseatLength = mDisplayMetrics.widthPixels;	
    // 	Margin计算
    View child = mContainer.getChildAt(0);
	DeviceProfile grid = mLauncher.getDeviceProfile();
    if (child == null) {
        mMargins = 0;
    } else {
        hotseatWidth = childcount*grid.hotseatBarSizePx+(childcount+1)*dip2px(15.0f);	// 已占用的长度
        mMargins = (hotseatLength - hotseatWidth) / 2;
    }
	Rect padding = grid.getHotseatLayoutPadding();
	mHotSeat.setPadding(dip2px(15.0f), padding.top, dip2px(15.0f), padding.bottom);
    //  设置Margin,居中显示 Hotseat
    FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mHotSeat.getLayoutParams();
	layoutParams.width = hotseatWidth;
	layoutParams.height = grid.hotseatBarSizePx;
    layoutParams.leftMargin = mMargins;
	layoutParams.gravity = Gravity.BOTTOM;
    mHotSeat.setLayoutParams(layoutParams);
    //  重载 Hotseat
    mHotSeat.requestLayout();	
}
//add core end

在实现Launcher3拖拽图标进入hotseat自适应布局功能实现二的核心功能中,通过上述的分析得知,
在DragDriver.java的核心功能中通过分析得知,在DragDriver create中,具体是由InternalDragDriver
处理拖拽响应事件,就可以在这里通过监听onTouchEvent(MotionEvent ev)事件,然后开始
在MotionEvent.ACTION_UP的事件中,调用resetLayout() 来重绘hotseat,
这时可以通过ShortcutAndWidgetContainer来获取多少个hotseat,然后就算hotseatWidth的宽度,
在设置相关参数来实现居中,最后调用mHotSeat.requestLayout();来刷新hotseat就可以实现
拖拽hotseat以后,同样实现居中功能

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-21 05:04:05       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-21 05:04:05       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-21 05:04:05       45 阅读
  4. Python语言-面向对象

    2024-07-21 05:04:05       55 阅读

热门阅读

  1. SpringBoot整合ElasticSearch

    2024-07-21 05:04:05       18 阅读
  2. 分层评估的艺术:sklearn中的策略与实践

    2024-07-21 05:04:05       20 阅读
  3. etcd磁盘空间故障处理办法

    2024-07-21 05:04:05       19 阅读
  4. sklearn中的增量学习:特征提取的艺术

    2024-07-21 05:04:05       20 阅读
  5. JVM的 6 种垃圾回收算法

    2024-07-21 05:04:05       20 阅读
  6. C语言中值滤波函数

    2024-07-21 05:04:05       19 阅读
  7. 【大模型基础】4.1 数据挖掘(待)

    2024-07-21 05:04:05       21 阅读