您的位置:首页 > 其它

通过Launcher里的WorkSpace完成桌面的3D转屏效果(有源码)

2011-08-13 19:52 302 查看
本帖最后由 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);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: