本帖最后由 ryan2010 于 2010-11-25 14:42 编辑 http://www.eoeandroid.com/thread-27079-1-1.html 大家复制起来研究太麻烦,要我上传附件,已经上传了,附件里面的改动比较大而且注释不那么详细了, 出于多效率的考虑,没有用多线程了。下面提到的问题也都已解决,有什么好的建议大家再提出来一起讨论。 这个workspace可以看做一个整体,X坐标上的范围是0-960 它共有3页,每个页即为一个child,每个child里面都有很多单元格,单元格中可以放置shortcut, active folder, widget,他们分别会横向纵向占用不同的单元格数。 通过使用ScrollTo(int,int)这个方法可以把workspace这个整体移动,来显示不同的页面 比如: ScrollTo(0,0) 为第一页 ScrollTo(320,0) 为第二页 ScrollTo(640,0) 为第三页 如果有更多页 ScrollTo(640,0) 为第四页 ScrollTo(960,0) 为第五页 . . . 其实页面上的被添加了组件后,这些组件我们看不见, 但是你点击某些看不见的“空位置”也是可以进入。 比如我们在中间页的左上角添加了一个短信的shortcut,如果不调用 drawChild(canvas, getChildAt(1), drawingTime)或者绘制出来我们是 看不见这个icon的,但是点击屏幕左上角却可以进入短信。 流程: 1.得到3个页的bitmap,页面上一有变化就重新得到bitmap 2.拖动屏幕时让屏幕不滑动也不按原始方式换页,而进行相应 的两个bitmap的变换操作来达到3D效果(不用GL,这样可以更有效率) 3.通过拖动的起始和结束坐标判断是否换页,应该如何换页 4.由于使用drawChild()把icon画到页上的时候,在进行2个bitmap的变换达到3D效果时 图像会出现从叠,故没有使用它,而是使用Canvas.drawBitmap()把相应bitmap张贴到 相应的页上,这样可以我们就可以知道屏幕的何处有何应用图标了 背景还没做好,准备搞个全黑,转的时候的3个Bitmap的背景搞成桌面背景,这样用户 还可以更换,3D效果有了,但需要改善 希望大家把自己的研究成果都分享出来,大家共同学习,共同进步 下面修改过的代码基都加以注释 */ package com.android.launcher; import java.util.ArrayList; import android.app.WallpaperManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Region; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; import android.widget.Scroller; import android.widget.TextView; public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller,Runnable { private static final int INVALID_SCREEN = -1; /** * The velocity at which a fling gesture will cause us to snap to the next screen */ private static final int SNAP_VELOCITY = 1000; private int mDefaultScreen; private final WallpaperManager mWallpaperManager; private boolean mFirstLayout = true; private int mCurrentScreen; private int mNextScreen = INVALID_SCREEN; private Scroller mScroller; private VelocityTracker mVelocityTracker; /** * CellInfo for the cell that is currently being dragged */ private CellLayout.CellInfo mDragInfo; /** * Target drop area calculated during last acceptDrop call. */ private int[] mTargetCell = null; private float mLastMotionX; private float mLastMotionY; private final static int TOUCH_STATE_REST = 0; private final static int TOUCH_STATE_SCROLLING = 1; private int mTouchState = TOUCH_STATE_REST; private OnLongClickListener mLongClickListener; private Launcher mLauncher; private DragController mDragger; /** * Cache of vacant cells, used during drag events and invalidated as needed. */ private CellLayout.CellInfo mVacantCache = null; private int[] mTempCell = new int[2]; private int[] mTempEstimate = new int[2]; private boolean mAllowLongPress; private boolean mLocked; private int mTouchSlop; private int mMaximumVelocity; final Rect mDrawerBounds = new Rect(); final Rect mClipBounds = new Rect(); int mDrawerContentHeight; int mDrawerContentWidth; //有3页,因此定义三个Bitmap用作3次截屏 private Bitmap[] s=new Bitmap[3]; //定义图片的大小 private float width=280; private float height=380; //定义矩阵和矩阵被绘制的方式,矩阵被用来做变换来让2张图片达到3D效果 private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Matrix mMatrix = new Matrix(); //用作绘制完成3D的参数 private float key=0.0f; //当前手在屏幕上的X坐标值,通过它判断2张图片要如何绘制 private float currentX=0; //判断拖动屏幕时的拖动方向,大于0为向右拖,小于0为向左拖 private float mdirection=0; //当拖动屏幕时,手刚接触到屏幕时的坐标,可以用来计算方向和跨度 private float startDragCoor=0; //用来得到startDragCoor时做判定 boolean flag=true; public Workspace(Context context, AttributeSet attrs) { this(context, attrs, 0); //设为true,因为下面要截图操作 setDrawingCacheEnabled(true); setDrawingCacheQuality(DRAWING_CACHE_QUALITY_HIGH); } public Workspace(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mWallpaperManager = WallpaperManager.getInstance(context); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0); //刚开机时 mDefaultScreen==1 mDefaultScreen = a.getInt(R.styleable.Workspace_defaultScreen, 1); a.recycle(); //设为true,因为下面要截图操作 setDrawingCacheEnabled(true); initWorkspace(); //新开一个线程,在拖动屏幕时更新 currentX 坐标并刷新屏幕,让2张图片变换达到3D效果 new Thread(this).start(); } private void initWorkspace() { mScroller = new Scroller(getContext()); mCurrentScreen = mDefaultScreen; Launcher.setScreen(mCurrentScreen); final ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); } @Override public void addView(View child, int index, LayoutParams params) { if (!(child instanceof CellLayout)) { throw new IllegalArgumentException("A Workspace can only have CellLayout children."); } super.addView(child, index, params); } @Override public void addView(View child) { super.addView(child); } @Override public void addView(View child, int index) { super.addView(child, index); } @Override public void addView(View child, int width, int height) { super.addView(child, width, height); } @Override public void addView(View child, LayoutParams params) { super.addView(child, params); } Folder getOpenFolder() { CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen); int count = currentScreen.getChildCount(); for (int i = 0; i < count; i++) { View child = currentScreen.getChildAt(i); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { return (Folder) child; } } return null; } ArrayList<Folder> getOpenFolders() { final int screens = getChildCount(); ArrayList<Folder> folders = new ArrayList<Folder>(screens); for (int screen = 0; screen < screens; screen++) { CellLayout currentScreen = (CellLayout) getChildAt(screen); int count = currentScreen.getChildCount(); for (int i = 0; i < count; i++) { View child = currentScreen.getChildAt(i); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { folders.add((Folder) child); break; } } } return folders; } //查看当前的页面是否为默认页面,及为中间的那个(共三个页面) boolean isDefaultScreenShowing() { return mCurrentScreen == mDefaultScreen; } //可查看当前是哪个页,0,1, 2 int getCurrentScreen() { return mCurrentScreen; } //通过scrollTo(int,int)这个方法来移动动屏幕,让它到达某个页面 //第一个参数为X坐标,第二个参数为Y坐标,由于有3页,故X范围是0 - 320*3 //如果把参数设置成(0,0)则当前为第一页,(320,0)为第二页,(640,0)为第三页 void setCurrentScreen(int currentScreen) { clearVacantCache(); mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1)); scrollTo(mCurrentScreen * getWidth(), 0); Log.d("Launcer D","Here we go"); invalidate(); } void addInCurrentScreen(View child, int x, int y, int spanX, int spanY) { addInScreen(child, mCurrentScreen, x, y, spanX, spanY, false); } void addInCurrentScreen(View child, int x, int y, int spanX, int spanY, boolean insert) { addInScreen(child, mCurrentScreen, x, y, spanX, spanY, insert); } void addInScreen(View child, int screen, int x, int y, int spanX, int spanY) { addInScreen(child, screen, x, y, spanX, spanY, false); } void addInScreen(View child, int screen, int x, int y, int spanX, int spanY, boolean insert) { if (screen < 0 || screen >= getChildCount()) { throw new IllegalStateException("The screen must be >= 0 and < " + getChildCount()); } clearVacantCache(); final CellLayout group = (CellLayout) getChildAt(screen); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); if (lp == null) { lp = new CellLayout.LayoutParams(x, y, spanX, spanY); } else { lp.cellX = x; lp.cellY = y; lp.cellHSpan = spanX; lp.cellVSpan = spanY; } group.addView(child, insert ? 0 : -1, lp); if (!(child instanceof Folder)) { child.setOnLongClickListener(mLongClickListener); } } void addWidget(View view, Widget widget, boolean insert) { addInScreen(view, widget.screen, widget.cellX, widget.cellY, widget.spanX, widget.spanY, insert); } CellLayout.CellInfo findAllVacantCells(boolean[] occupied) { CellLayout group = (CellLayout) getChildAt(mCurrentScreen); if (group != null) { return group.findAllVacantCells(occupied, null); } return null; } CellLayout.CellInfo findAllVacantCellsFromModel() { CellLayout group = (CellLayout) getChildAt(mCurrentScreen); if (group != null) { int countX = group.getCountX(); int countY = group.getCountY(); boolean occupied[][] = new boolean[countX][countY]; Launcher.getModel().findAllOccupiedCells(occupied, countX, countY, mCurrentScreen); return group.findAllVacantCellsFromOccupied(occupied, countX, countY); } return null; } private void clearVacantCache() { if (mVacantCache != null) { mVacantCache.clearVacantCells(); mVacantCache = null; } } @Override public void setOnLongClickListener(OnLongClickListener l) { mLongClickListener = l; final int count = getChildCount(); for (int i = 0; i < count; i++) { getChildAt(i).setOnLongClickListener(l); } } private void updateWallpaperOffset() { updateWallpaperOffset(getChildAt(getChildCount() - 1).getRight() - (mRight - mLeft)); } //当我们移动屏幕时,壁纸也会移动,但前提是壁纸一定要比页面大小大 private void updateWallpaperOffset(int scrollRange) { mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 ); //下面这个方法带两参数X Y, X should be 0.0-1.0,if there are 3 screens // X can be 0.0 0.5 1.0, to represents the 3 screens mWallpaperManager.setWallpaperOffsets(getWindowToken(), mScrollX / (float) scrollRange, 0); } |