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\CellLayout.java
3.Launcher3拖拽图标进入hotseat自适应布局功能实现三的核心功能分析和实现
Launcher顾名思义,就是桌面的意思,也是android系统启动后第一个启动的应用程序,
:Launcher3负责管理和展示用户手机桌面上的各个应用程序图标。它通过GridView或者LinearLayout等布局管理器将
图标进行排列,并支持滑动、放大缩小等手势操作
Hotseat也是属于在导航栏底部的BubbleTextView的布局,只是不显示app图标
CellLayout:主屏幕中的每一页,其父布局就是Workspace,左右滑动屏幕,就是每一个CellLayout的变化过程,这个类中有很多处理拖拽相关方法
3.1 新增一部分关于处理拖拽图标重叠的工具类
在实现Launcher3拖拽图标进入hotseat自适应布局功能实现三中,通过分析得知,在进行
一些拖拽的过程中,在只有两个三个hotseat的时候,这时候会出现hotseat重叠的问题,这时候就需要先清除掉hotseat的所有view,然后添加hotseat,
package com.android.launcher3.util;
import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.ItemInfo;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
import java.util.ArrayList;
public class HotseatController{
private static final String TAG = "HotseatController";
private static final int INVALID = -1;
private boolean mDelayClearEmptyGridFlag = false;
private CellLayout.CellInfo mBackupDragInfo = null;
private LauncherAppMonitor mMonitor;
protected Context mContext;
public HotseatController(Context context, LauncherAppMonitor monitor) {
this.mContext = context;
mMonitor = monitor;
}
public boolean isFull(Launcher launcher) {
if (launcher == null) {
return false;
}
Hotseat hs = launcher.getHotseat();
int gridCount = getGridCount(launcher);
for (int i = 0; i < gridCount; i++) {
int cx = hs.getCellXFromOrder(i);
int cy = hs.getCellYFromOrder(i);
if (!hs.isOccupied(cx, cy)) {
return false;
}
}
return true;
}
public boolean clearEmptyGrid(Launcher launcher) {
if (launcher == null) {
Log.e(TAG, "launcher is null, clear empty grid failed.");
return false;
}
if (isFull(launcher)) {
Log.d(TAG, "there are no empty grid in hotseat, no need to clear.");
return false;
}
if (mDelayClearEmptyGridFlag) {
Log.d(TAG, "mDelayClearEmptyGridFlag is true, to clear empty when it is false.");
return false;
}
ArrayList<View> views = backupHotseatChildren(launcher);
if (views.size() == 0) {
return false;
}
Hotseat hs = launcher.getHotseat();
boolean isLandscape = hs.mHasVerticalHotseat;
int count = views.size();
int countX = isLandscape ? 1 : Math.max(count, 1);
int countY = isLandscape ? Math.max(count, 1) : 1;
if(count>1){
hs.removeAllViews();
}else{
hs.removeView(views.get(0));
}
hs.setGridSize(countX, countY);
for (int i = 0; i < count; i++) {
if (!addViewToHotseat(launcher, views.get(i), i)) {
Log.e("Hotseat", "failed to add view to hotseat, rank:" + i);
}
}
updateFolderIconLeaveBehind(launcher);
return true;
}
public int dip2px(float dpValue,Launcher launcher) {
final float scale = launcher.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
private void updateFolderIconLeaveBehind(Launcher launcher) {
Folder folder = Folder.getOpen(launcher);
if (folder != null && folder.mInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
folder.getFolderIcon().drawLeaveBehindIfExists();
}
}
public boolean addViewToHotseat(Launcher launcher, View v, int rank) {
Hotseat hs = launcher.getHotseat();
if (v != null && rank < getGridCount(launcher)) {
int cellX = hs.getCellXFromOrder(rank);
int cellY = hs.getCellYFromOrder(rank);
if (v.getTag() instanceof ItemInfo) {
CellLayout.LayoutParams lp = new CellLayout.LayoutParams(cellX, cellY, 1, 1);
if (hs.addViewToCellLayout(v, -1, v.getId(), lp, true)) {
((ItemInfo)v.getTag()).screenId = rank;
if (true) {
Log.d(TAG, "update " + ((ItemInfo)v.getTag()).title + " to:" + rank);
}
return true;
}
}
}
return false;
}
public void resetDragCell(Launcher launcher, CellLayout.CellInfo cellInfo) {
if (cellInfo == null || cellInfo.cell == null) {
if (cellInfo != null) {
Log.d(TAG, "cell is null, can not reset cell to original position.");
}
return;
}
if (cellInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
View v = cellInfo.cell;
Hotseat hs = launcher.getHotseat();
int gridCount = getGridCount(launcher);
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
int index = getOrderInHotseat(launcher, lp.cellX, lp.cellY, gridCount + 1);
if (index >= gridCount) {
insertEmptyGrid(launcher, gridCount);
} else {
int cx = hs.getCellXFromOrder(index);
int cy = hs.getCellYFromOrder(index);
if (hs.isOccupied(cx, cy)) {
insertEmptyGrid(launcher, index);
}
}
if (addViewToHotseat(launcher, v, index)) {
v.setVisibility(View.VISIBLE);
Log.d(TAG, "resetDragCell to :" + index);
}
}
}
public int calculateBestIndex(Launcher launcher, float[] dragViewVisualCenterint,
int findCellX, int findCellY) {
Hotseat hs = launcher.getHotseat();
int index = getOrderInHotseat(launcher, findCellX, findCellY);
int[] cellCenter = new int[2];
hs.cellToCenterPoint(findCellX, findCellY, cellCenter);
boolean isDragInEndArea = hs.mHasVerticalHotseat ?
dragViewVisualCenterint[1] < cellCenter[1] : dragViewVisualCenterint[0] > cellCenter[0];
return isDragInEndArea ? index + 1 : index;
}
public boolean insertEmptyGrid(Launcher launcher, int index) {
if (launcher == null) {
Log.d(TAG, "launcher is null, insert empty grid failed.");
return false;
}
if (!canInsert(launcher)) {
Log.d(TAG, "achieve maximum limit, can not insert empty grid.");
return false;
}
if (!isFull(launcher)) {
Log.d(TAG, "the hotseat has empty grid, can not insert empty grid.");
return false;
}
ArrayList<View> views = backupHotseatChildren(launcher);
Hotseat hs = launcher.getHotseat();
final boolean isLandscape = hs.mHasVerticalHotseat;
int newCount = views.size() + 1;
int countX = isLandscape ? 1 : newCount;
int countY = isLandscape ? newCount : 1;
if(views.size()>1){
hs.removeAllViews();
}else{
hs.removeView(views.get(0));
}
hs.setGridSize(countX, countY);
for (int i = 0; i < views.size(); i++) {
View view = views.get(i);
if (i < index) {
addViewToHotseat(launcher, view, i);
} else {
addViewToHotseat(launcher, view, i + 1);
}
if (view.getTag() instanceof ItemInfo) {
launcher.getModelWriter().updateItemInDatabase((ItemInfo) view.getTag());
}
}
return true;
}
private ArrayList<View> backupHotseatChildren(Launcher launcher) {
Hotseat hs = launcher.getHotseat();
int gridCount = getGridCount(launcher);
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 (true) {
Log.d(TAG, "backup child:" + i);
}
views.add(v);
}
}
}
return views;
}
public void resetGridIfNeeded(Launcher launcher, int index) {
if (launcher == null) {
return;
}
if (!isCellOccupied(launcher)) {
insertEmptyGrid(launcher, index);
}
}
public boolean isCellOccupied(Launcher launcher) {
if (launcher == null) {
return false;
}
Hotseat hs = launcher.getHotseat();
int gridCount = getGridCount(launcher);
if (gridCount == 1) {
if (!hs.isOccupied(0, 0)) {
return true;
}
}
return false;
}
public int getGridCount(Launcher launcher) {
if (launcher == null) {
Log.d(TAG, "launcher is null, can not get grid count.");
return INVALID;
}
Hotseat hs = launcher.getHotseat();
return hs.mHasVerticalHotseat ? hs.getCountY() : hs.getCountX();
}
public boolean canInsert(Launcher launcher) {
int gridCount = getGridCount(launcher);
return gridCount < launcher.getDeviceProfile().inv.numHotseatIcons;
}
public void backupDragInfo(CellLayout.CellInfo cellInfo) {
mBackupDragInfo = cellInfo;
}
public CellLayout.CellInfo getBackupDragInfo () {
return mBackupDragInfo;
}
public void setDelayClearEmptyGridFlag(boolean falg) {
mDelayClearEmptyGridFlag = falg;
}
public boolean isNeedInterceptHotseatTouch(MotionEvent event, View view) {
boolean needIntercept = false;
if (view != null && view.getTag() instanceof ItemInfo) {
if (((ItemInfo) view.getTag()).container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
int iconSize = 0;
if (view instanceof FolderIcon) {
iconSize = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext).folderIconSizePx;
} else if (view instanceof BubbleTextView) {
iconSize = ((BubbleTextView) view).getIconSize();
}
// we'll intercept touch event when touch in blank area in hotseat.
needIntercept = !getIconRect(iconSize, view)
.contains((int) event.getX() + view.getScrollX(),
(int) event.getY() + view.getScrollY());
}
}
return needIntercept;
}
public static Rect getIconRect(int iconSize, View view) {
Point center = new Point(view.getScrollX() + (view.getWidth() >> 1),
view.getScrollY() + view.getPaddingTop() + (iconSize >> 1));
Rect iconRect = new Rect();
iconRect.left = center.x - (iconSize >> 1);
iconRect.top = center.y - (iconSize >> 1);
iconRect.right = iconRect.left + iconSize;
iconRect.bottom = iconRect.top + iconSize;
return iconRect;
}
public int getOrderInHotseat(Launcher launcher, int x, int y) {
return getOrderInHotseat(launcher, x, y, getGridCount(launcher));
}
public int getOrderInHotseat(Launcher launcher, int x, int y, int gridCount) {
if (launcher == null) {
Log.d(TAG, "launcher is null, can not get order in hotseat.");
return INVALID;
}
return launcher.getHotseat().mHasVerticalHotseat ? (gridCount - y - 1) : x;
}
}
在实现Launcher3拖拽图标进入hotseat自适应布局功能实现三中,通过分析得知,
在新增的HotseatController.java的相关源码中,在这个类中,主要就是处理当hotseat图标拖拽出
Hotseat的区域时,或者其他图标拖拽进入hotseat的时候,就会调用clearEmptyGrid(Launcher launcher)
来进行相关的拖拽清理图标功能,在增加或减少hotseat的时候,会先清理掉hotseat的所有图标,
然后在addViewToHotseat(launcher, views.get(i), i)插入hotseat到布局中,就实现了去掉hotseat
重复的功能,
package com.android.launcher3.util;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ShortcutInfo;
import android.database.sqlite.SQLiteDatabase;
import android.os.UserHandle;
import android.util.Log;
import android.text.TextUtils;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.util.MainThreadInitializedObject;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LauncherAppMonitor {
private static final String TAG = "LauncherAppMonitor";
// We do not need any synchronization for this variable as its only written on UI thread.
public static final MainThreadInitializedObject<LauncherAppMonitor> INSTANCE =
new MainThreadInitializedObject<>(LauncherAppMonitor::new);
private final ArrayList<WeakReference<LauncherAppMonitorCallback>> mCallbacks = new ArrayList<>();
private HotseatController mHotseatController = null;
private Launcher mLauncher;
public static LauncherAppMonitor getInstance(final Context context) {
return INSTANCE.get(context.getApplicationContext());
}
public static LauncherAppMonitor getInstanceNoCreate() {
return INSTANCE.getNoCreate();
}
//return null while launcher activity isn't running
public Launcher getLauncher() {
return mLauncher;
}
public void unregisterCallback(LauncherAppMonitorCallback callback) {
for (int i = mCallbacks.size() - 1; i >= 0; i--) {
if (mCallbacks.get(i).get() == callback) {
synchronized (mCallbacks) {
mCallbacks.remove(i);
}
}
}
}
public void registerCallback(LauncherAppMonitorCallback callback) {
// Prevent adding duplicate callbacks
unregisterCallback(callback);
synchronized (mCallbacks) {
mCallbacks.add(new WeakReference<>(callback));
}
}
private LauncherAppMonitor(Context context) {
mHotseatController = new HotseatController(context, this);
}
public void onRecentsActivityCreate(BaseDraggingActivity activity) {
Log.d(TAG,"onRecentsActivityCreate");
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onRecentsActivityCreate(activity);
}
}
}
public void onRecentsActivityStart() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onRecentsActivityStart();
}
}
}
public void onQuickstepLauncherStart() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onQuickstepLauncherStart();
}
}
}
public void onLauncherPreCreate(Launcher launcher) {
if (mLauncher != null) {
onLauncherDestroy(mLauncher);
}
mLauncher = launcher;
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherPreCreate(launcher);
}
}
}
public void onLauncherCreated() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherCreated();
}
}
}
public void onLauncherPreResume() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherPreResume();
}
}
}
public void onLauncherResumed() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherResumed();
}
}
}
public void onLauncherPrePause() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherPrePaused();
}
}
}
public void onLauncherPaused() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherPaused();
}
}
}
public void onLauncherStart() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherStart();
}
}
}
public void onLauncherStop() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherStop();
}
}
}
public void onLauncherDestroy(Launcher launcher) {
if (launcher != mLauncher) {
return;
}
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherDestroy();
}
}
mLauncher = null;
}
public void onLauncherRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
public void onSettingsActivityRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onSettingsActivityRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
public void onLauncherFocusChanged(boolean hasFocus) {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onLauncherFocusChanged(hasFocus);
}
}
}
public void onReceiveHomeIntent() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onHomeIntent();
}
}
}
public void onLauncherWorkspaceBindingFinish() {
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onBindingWorkspaceFinish();
}
}
}
public void onLauncherAllAppBindingFinish(AppInfo[] apps) {
if (true) {
for (AppInfo app : apps) {
Log.d("Load app ", app.toComponentKey().toString() + "\n");
}
}
for (int i = 0; i < mCallbacks.size(); i++) {
LauncherAppMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onBindingAllAppFinish(apps);
}
}
}
public HotseatController getHotseatController() {
return mHotseatController;
}
}
在实现Launcher3拖拽图标进入hotseat自适应布局功能实现三中,通过分析得知,
在新增的util下的LauncherAppMonitor的这个类中,这个类的主要功能就是在
Launcher.java中负责绑定app的功能,在每个生命周期执行不同的方法,实现不同的
功能,作为实现功能的辅助类功能
原文地址:https://blog.csdn.net/baidu_41666295/article/details/140571803
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!