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以后,同样实现居中功能