1.最近公司項(xiàng)目有個(gè)需求需要定制系統(tǒng)桌面并且實(shí)現(xiàn)無限循環(huán)滑動(dòng)俏讹,通過主窗口的layout我們可以得到系統(tǒng)桌面的分頁是通過Workspace來實(shí)現(xiàn)的伟葫;
2.通過代碼可以知道Workspace 繼承自PagedView穿稳,而pagedview的效果和viewpager其實(shí)類似,那么久簡(jiǎn)單了恰梢,那么我們通過復(fù)制首尾兩屏的頁面數(shù)據(jù)然后分別插入首尾兩個(gè)部分就行藻烤,這里應(yīng)用了這位小朋友的圖片來做說明。
3.那么接下來就是首尾兩頁數(shù)據(jù)的數(shù)據(jù)備份了妥泉,方式1就是在bind數(shù)據(jù)的時(shí)候記錄首尾兩頁數(shù)據(jù)的子項(xiàng)了椭微,然后再add到相對(duì)于新增的首尾兩個(gè)celllayout里面去,但是這樣的話太麻煩了尤其是還要去更新各種拖動(dòng)移除后的數(shù)據(jù)盲链;
4.通過源碼中的bindItems 方法可以得知蝇率,每個(gè)子item項(xiàng)目的tag其實(shí)就是bindItems迟杂,所以就不用去記錄首尾兩頁數(shù)據(jù)的數(shù)據(jù)了,直接通過view獲取item本慕,然后在逐個(gè)去添加就好了排拷;
5.廢話不多說了,直接上代碼
package com.android.launcher3;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.touch.ItemLongClickListener;
/**
* 定義一個(gè)可以循環(huán)滾動(dòng)的Workspace
*/
public class CycleWorkspaceextends Workspace {
private static final StringTAG ="CycleWorkspace";
//第一頁的ID
? ? public static final int FIRST_SCREEN_ID = -1001;
//最后一頁的ID
? ? public static final int LAST_SCREEN_ID =1001;
CellLayoutmEndCellLayout,mStartCellLayout;
public CycleWorkspace(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CycleWorkspace(Context context, AttributeSet attrs,int defStyle) {
super(context, attrs, defStyle);
}
/**
? ? * copy 一份最后的頁面存放在首位
? ? */
? ? public void addFirstCellLayout(){
//Log.e(TAG,"ScreenOrderID ="+mScreenOrder.get(mScreenOrder.size()-1));
? ? ? ? CellLayout cellLayout=? getScreenWithId(mScreenOrder.get(mScreenOrder.size()-1));
if (cellLayout.getChildCount()>0) {
ViewGroup viewGroup = (ViewGroup) cellLayout.getChildAt(0);
//Log.e(TAG, "addFirstCellLayout viewGroups=" + viewGroup.getChildCount());
? ? ? ? ? ? if (mStartCellLayout ==null) {
mStartCellLayout = copyInsertNewWorkspaceScreen(0);
mStartCellLayout.setId(FIRST_SCREEN_ID);
}else {
if (getChildAt(0).getId() !=FIRST_SCREEN_ID) {
addView(mStartCellLayout,0);
}
}? ? ? ? ? ? ? ?
mStartCellLayout.removeAllViews();
if (viewGroup.getChildCount() >0) {
//設(shè)置endCellLayout的view
for (int i =0; i < viewGroup.getChildCount(); i++) {
ItemInfo item = (ItemInfo) viewGroup.getChildAt(i).getTag();
View view =null;
if (iteminstanceof WorkspaceItemInfo) {
WorkspaceItemInfo info = (WorkspaceItemInfo) item;
view =mLauncher.createShortcut(viewGroup, info);
}else if (iteminstanceof FolderInfo) {
view = FolderIcon.fromXml(R.layout.folder_icon,mLauncher,viewGroup, (FolderInfo) item);
}else if (iteminstanceof LauncherAppWidgetInfo) {
view =mLauncher.inflateAppWidget((LauncherAppWidgetInfo) item);
}
if (view ==null) {
continue;
}
addCopyInScreen(view, item.cellX, item.cellY, item.spanX, item.spanY,mStartCellLayout);
}
}
}
}
/**
? ? * copy 首頁一份最后的頁面存放在最后面
? ? */
? ? public void addEndCellLayout(){
CellLayout cellLayout=? getScreenWithId(mScreenOrder.get(0));
//Log.e(TAG, "addEndCellLayout cellLayout=" + cellLayout);
? ? ? ? if (cellLayout.getChildCount()>0) {
if (mEndCellLayout ==null) {
mEndCellLayout = copyNewFirstWorkspaceScreen(getChildCount());
mEndCellLayout.setId(LAST_SCREEN_ID);
}else {
if (getChildAt(getChildCount()-1).getId() !=LAST_SCREEN_ID) {
addView(mEndCellLayout, getChildCount());
}
}
ViewGroup viewGroup = (ViewGroup) cellLayout.getChildAt(0);
//Log.e(TAG, "addEndCellLayout viewGroups=" + viewGroup.getChildCount());
mEndCellLayout.removeAllViews();
? ? ? ? ? ? if (viewGroup.getChildCount() >0) {
mEndCellLayout.removeAllViews();
for (int i =0; i < viewGroup.getChildCount(); i++) {
if (i==0){
if (mQsb !=null) {
CellLayout.LayoutParams lp =new CellLayout.LayoutParams(0,0,mEndCellLayout.getCountX(),1);
lp.canReorder =false;
mEndCellLayout.addViewToCellLayout(mQsb,0, R.id.copy_search_container_workspace, lp,true);
}
}else {
ItemInfo item = (ItemInfo) viewGroup.getChildAt(i).getTag();
View view =null;
if (iteminstanceof WorkspaceItemInfo) {
WorkspaceItemInfo info = (WorkspaceItemInfo) item;
view =mLauncher.createShortcut(viewGroup, info);
}else if (iteminstanceof FolderInfo) {
view = FolderIcon.fromXml(R.layout.folder_icon,mLauncher, viewGroup, (FolderInfo) item);
}else if (iteminstanceof LauncherAppWidgetInfo) {
view =mLauncher.inflateAppWidget((LauncherAppWidgetInfo) item);
}
if (view ==null) {
continue;
}
addCopyInScreen(view,? item.cellX, item.cellY, item.spanX, item.spanY,mEndCellLayout);
}
}
}
}
}
private void addCopyInScreen(View child,int x,int y,
int spanX,int spanY,CellLayout layout) {
//Log.e(TAG,"instanceof child ="+(child instanceof FolderIcon));
? ? ? ? if (childinstanceof FolderIcon) {
((FolderIcon) child).setTextVisible(true);
}
LayoutParams genericLp = child.getLayoutParams();
CellLayout.LayoutParams lp;
if (!(genericLpinstanceof CellLayout.LayoutParams)) {
lp =new CellLayout.LayoutParams(x, y, spanX, spanY);
}else {
lp = (CellLayout.LayoutParams) genericLp;
lp.cellX = x;
lp.cellY = y;
lp.cellHSpan = spanX;
lp.cellVSpan = spanY;
}
if (spanX <0 && spanY <0) {
lp.isLockedToGrid =false;
}
// Get the canonical child id to uniquely represent this view in this screen
? ? ? ? ItemInfo info = (ItemInfo) child.getTag();
int childId = info.id;
//Log.e(TAG,"childId ="+childId);
? ? ? ? boolean markCellsAsOccupied = !(childinstanceof Folder);
//Log.e(TAG,"markCellsAsOccupied ="+markCellsAsOccupied);
? ? ? ? if (!layout.addViewToCellLayout(child, -1, childId, lp, markCellsAsOccupied)) {
// TODO: This branch occurs when the workspace is adding views
? ? ? ? ? ? // outside of the defined grid
// maybe we should be deleting these items from the LauncherModel?
? ? ? ? ? ? Log.e(TAG,"Failed to add to item at (" + lp.cellX +"," + lp.cellY +") to CellLayout");
}
child.setHapticFeedbackEnabled(false);
child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
if (childinstanceof DropTarget) {
Log.e(TAG,"addDropTarget ="+child);
mDragController.addDropTarget((DropTarget) child);
}
}
ViewmQsb=null;
public CellLayout copyNewFirstWorkspaceScreen(int insertIndex) {
CellLayout endPage = copyInsertNewWorkspaceScreen(insertIndex);
// Always add a QSB on the first screen.
? ? ? ? if (mQsb ==null) {
// In transposed layout, we add the QSB in the Grid. As workspace does not touch the
// edges, we do not need a full width QSB.
? ? ? ? ? ? mQsb = LayoutInflater.from(getContext())
.inflate(R.layout.copy_search_container_workspace, endPage,false);
}
CellLayout.LayoutParams lp =new CellLayout.LayoutParams(0,0, endPage.getCountX(),1);
lp.canReorder =false;
if (!endPage.addViewToCellLayout(mQsb,0, R.id.copy_search_container_workspace, lp,true)) {
Log.e(TAG,"Failed to add to item at (0, 0) to CellLayout");
}
return endPage;
}
public CellLayout copyInsertNewWorkspaceScreen(int insertIndex) {
// Inflate the cell layout, but do not add it automatically so that we can get the newly
// created CellLayout.
? ? ? ? CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen,this,false );
newScreen.getShortcutsAndWidgets().setId(R.id.workspace_page_container);
int paddingLeftRight =mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
int paddingBottom =mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx;
newScreen.setPadding(paddingLeftRight,0, paddingLeftRight, paddingBottom);
addView(newScreen, insertIndex);
mStateTransitionAnimation.applyChildState(
mLauncher.getStateManager().getState(), newScreen, insertIndex);
if (mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
newScreen.enableAccessibleDrag(true, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
}
return newScreen;
}
@Override
? ? protected void onPageEndTransition() {
super.onPageEndTransition();
Log.e(TAG,"onPageEndTransition");
if (CYCLE_MODE && getPageCount()>1){//處理滑動(dòng)完成后頁面切換锅尘,實(shí)現(xiàn)循環(huán)效果
? ? ? ? ? ? if (getCurrentPage() == getPageCount() -1) {
addFirstCellLayout();
CellLayout curCellLayout = (CellLayout) getPageAt(getCurrentPage());
if (curCellLayout !=null && curCellLayout.getId() ==LAST_SCREEN_ID) {
//切換到第一頁
? ? ? ? ? ? ? ? ? ? setCurrentPage(1);
}
}else if (getCurrentPage() ==0) {
addEndCellLayout();
CellLayout curCellLayout = (CellLayout) getPageAt(getCurrentPage());
if (curCellLayout !=null && curCellLayout.getId() ==FIRST_SCREEN_ID) {
//切換到最后一頁
? ? ? ? ? ? ? ? ? ? setCurrentPage(getChildCount() -2);
}
}
}
}
@Override
? ? protected void onPageBeginTransition() {
super.onPageBeginTransition();
}
//記錄拖動(dòng)前的分頁數(shù)量
private int mPageCount=0;
@Override
? ? public void onDragStart(DragObject dragObject, DragOptions options) {
if (CYCLE_MODE && getPageCount()>2){//移除首位兩個(gè)View
? ? ? ? ? ? removeViewAt(getChildCount()-1);
removeViewAt(0);}
super.onDragStart(dragObject, options);
mPageCount=getPageCount();
Log.e(TAG,"onDragStart mPageCount="+mPageCount);
}
@Override
? ? public void onDragEnd() {
super.onDragEnd();
int pageCount=getPageCount();
Log.e(TAG,"onDragEnd currentPage="+getCurrentPage() +",pageCount="+pageCount );
if (CYCLE_MODE && getPageCount()>1){
int cur =getCurrentPage();
addFirstCellLayout();
addEndCellLayout();
//如果添加了分頁或者不變則切換當(dāng)前的分頁位置监氢,如果減少了位置則保持不變,避免出現(xiàn)空屏(子view 還未繪制完)的情況
? ? ? ? ? ? if (pageCount<=mPageCount){
++cur;
setCurrentPage(cur);
}
}
}
}