Recents 即多任务界面,显示最近使用过的APP List的。下面内容都是基于Android 11平台修改的。Android 11上,Recents 这一部分代码其实都已经被挪到Launcher3中。由于个人习惯,所以将内容分类作为SystemUI部分记录。
多任务界面主要几个文件:
TaskView.java | app卡片 |
ClearAllButton.java | 全部清除Button |
OverviewActionsView.java | 多任务界面下方View,包含截图等按钮 |
RecentsView.java | 主界面,集成PageView,包含所有TaskView与ClearAllButton |
源码中,RecentsView 默认采用 Rtl 布局的方式(猜测这个设计是不是因为Recents按键一般在右下角,用户右手操作多,点进去RecentsView直接右滑更舒服)。界面整体布局如下图:
默认从左往右滑动,RecentsView 最后一个子View就是 ClearAllButton。我们尝试将 ClearAllButton 放置到 RecentsView 的第一位,做成如下效果。左滑直接可以点击清除,右滑查看历史APP卡片。
第一步,调整子View顺序。在 RecentsView.java 中,addView 时候换下顺序,先加载 ClearAllButton ,再去加载最新打开的 APP 的 TaskView 控件,最后加载历史 TaskView 控件。调整代码:
@@ -408,7 +408,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
private boolean mLiveTileOverlayAttached;
// Keeps track of the index where the first TaskView should be
- private int mTaskViewStartIndex = 0;
+ // 全部清除按钮放置在PageView的0位,TaskView 下标应该从1开始
+ private int mTaskViewStartIndex = 1;
private OverviewActionsView mActionsView;
private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
@@ -622,7 +623,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
if (!(affectingView instanceof TaskView) && !(affectingView instanceof ClearAllButton)) {
int childCount = getChildCount();
- mTaskViewStartIndex = 0;
+ // 全部清除按钮放置在PageView的0位,TaskView 下标应该从1开始
+ mTaskViewStartIndex = 1;
while (mTaskViewStartIndex < childCount
&& !(getChildAt(mTaskViewStartIndex) instanceof TaskView)) {
mTaskViewStartIndex++;
@@ -679,13 +681,17 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
@Override
protected void onPageBeginTransition() {
super.onPageBeginTransition();
+ // 滑动开始的时候,会把截图按钮设置为禁用状态,防止误点击
+ android.util.Log.i("TA", "onPageBeginTransition true " + OverviewActionsView.DISABLED_SCROLLING);
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, true);
}
@Override
protected void onPageEndTransition() {
super.onPageEndTransition();
+ // 滑动结束的时候,如果isClearAllHidden为true(即当前不在全部清除按钮界面)。将截图按钮设置为可用状态
if (isClearAllHidden()) {
+ android.util.Log.i("TA", "onPageEndTransition false " + OverviewActionsView.DISABLED_SCROLLING);
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
}
if (getNextPage() > 0) {
@@ -782,18 +788,20 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
final int requiredTaskCount = tasks.size();
if (getTaskViewCount() != requiredTaskCount) {
- if (indexOfChild(mClearAllButton) != -1) {
+ /*if (indexOfChild(mClearAllButton) != -1) {
removeView(mClearAllButton);
- }
+ }*/
+ //逐个添加TaskView到PageView
for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
addView(mTaskViewPool.getView());
}
+ //全部清除Button提前到前面添加,保证是PageView的第0个Child View
+ /*if (requiredTaskCount > 0) {
+ addView(mClearAllButton);
+ }*/
while (getTaskViewCount() > requiredTaskCount) {
removeView(getChildAt(getChildCount() - 1));
}
- if (requiredTaskCount > 0) {
- addView(mClearAllButton);
- }
}
// Rebind and reset all task views
@@ -840,9 +848,10 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
public int getTaskViewCount() {
int taskViewCount = getChildCount() - mTaskViewStartIndex;
- if (indexOfChild(mClearAllButton) != -1) {
+ // mClearAllButton放置在0位了,所以taskViewCount直接 = getChildCount() - mTaskViewStartIndex,不用再--
+ /*if (indexOfChild(mClearAllButton) != -1) {
taskViewCount--;
- }
+ }*/
return taskViewCount;
}
@@ -854,7 +863,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
TaskView taskView = getTaskViewAt(i);
- if (mIgnoreResetTaskId != taskView.getTask().key.id) {
+ if (taskView.getTask() == null || taskView.getTask().key.id != mIgnoreResetTaskId) {
taskView.resetViewTransforms();
taskView.setStableAlpha(mContentAlpha);
taskView.setFullscreenProgress(mFullscreenProgress);
@@ -955,6 +964,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
return;
}
mOrientationHandler.getCurveProperties(this, mInsets, mScrollState);
+ mScrollState.maxScroll = mMaxScroll;
mScrollState.scrollFromEdge =
mIsRtl ? mScrollState.scroll : (mMaxScroll - mScrollState.scroll);
@@ -1193,14 +1203,15 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
* is called. Also scrolls the view to this task.
*/
public void showCurrentTask(RunningTaskInfo runningTaskInfo) {
- if (shouldAddDummyTaskView(runningTaskInfo)) {
- boolean wasEmpty = getChildCount() == 0;
- // Add an empty view for now until the task plan is loaded and applied
+ //全部清除Button提前到前面添加,保证是PageView的第0个Child View
+ if (indexOfChild(mClearAllButton) != -1) {
+ removeView(mClearAllButton);
+ }
+ addView(mClearAllButton, 0);
+ if (shouldAddDummyTaskView(runningTaskInfo)) {//有新增app
final TaskView taskView = mTaskViewPool.getView();
+ //添加最新的app taskview,是PageView的第1个Child View
addView(taskView, mTaskViewStartIndex);
- if (wasEmpty) {
- addView(mClearAllButton);
- }
// The temporary running task is only used for the duration between the start of the
// gesture and the task list is loaded and applied
mTmpRunningTask = Task.from(new TaskKey(runningTaskInfo), runningTaskInfo, false);
@@ -1381,6 +1392,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
*/
public float scrollFromEdge;
+ public float maxScroll;
+
/**
* Updates linearInterpolation for the provided child position
*/
@@ -2272,7 +2285,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
}
@Override
- protected int computeMinScroll() {
+ protected int computeMinScroll() {//获取最左边的范围
if (getTaskViewCount() > 0) {
if (mDisallowScrollToClearAll) {
// We aren't showing the clear all button,
@@ -2283,7 +2296,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
return getScrollForPage(mTaskViewStartIndex);
}
if (mIsRtl) {
- return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
+ //获取可以滑动的范围,ClearAllButton换到0位后,最后一个就是 TaskView ,无需+1了
+ return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
}
return getScrollForPage(mTaskViewStartIndex);
}
@@ -2291,20 +2305,21 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
}
@Override
- protected int computeMaxScroll() {
+ protected int computeMaxScroll() {//获取最右边的范围
if (getTaskViewCount() > 0) {
if (mDisallowScrollToClearAll) {
// We aren't showing the clear all button,
// so use the rightmost task as the min scroll.
if (mIsRtl) {
- return getScrollForPage(mTaskViewStartIndex);
+ return getScrollForPage(0);
}
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
}
if (mIsRtl) {
- return getScrollForPage(mTaskViewStartIndex);
+ //获取可以滑动的范围,mTaskViewStartIndex当前是1,所以直接这里写死成0就行
+ return getScrollForPage(0);
}
- return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
+ return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
}
return super.computeMaxScroll();
}
修改顺序后,会导致 ClearAllButton 是否显示的计算方法不匹配(默认是滑到最左边显示),导致 ClearAllButton 不显示。同时,OverviewActionsView 中截图功能也是根据 ClearAllButton 的状态判断当前能否显示截图。所以需要再调整下 ClearAllButton 的显示计算方法。
@@ -100,13 +102,16 @@ public class ClearAllButton extends Button implements PageCallbacks {
float shift = Math.min(scrollState.scrollFromEdge, orientationSize);
float translation = mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift);
orientationHandler.setPrimaryAndResetSecondaryTranslate(this, translation);
- mScrollAlpha = 1 - shift / orientationSize;
+ // 这里是左右滑动时候,按照View滑动的距离,确定clearAllbutton是否需要显示
+ mScrollAlpha = scrollState.maxScroll == scrollState.scrollFromEdge ? 1.0f : 0.0f;
updateAlpha();
}
private void updateAlpha() {
final float alpha = mScrollAlpha * mContentAlpha * mVisibilityAlpha;
setAlpha(alpha);
+ // 根据mScrollAlpha(滑动参数)、mContentAlpha(是否存在)、mVisibilityAlpha(是否设置不可见)来确定clearAllbutton是否可见
+ android.util.Log.i("TA", "updateAlpha " + alpha);
setClickable(alpha == 1);
}
这里新加一个属性 scrollState.maxScroll 表示最大滑动范围值, scrollFromEdge 等于 maxScroll 时,表示滑到最右边了,此时是 ClearAllButton 界面,ClearAllButton 显示。其他界面就不显示了。
计算 ClearAllButton 显示方法上面这种的话,你是必须滑到最右边才行。如果在第一个APP卡片界面,是不显示,看着不太好看,如下图: