Launcher2 分析

编译Launcher2

这是我已经编辑过后的代码: https://github.com/sevenler/Android_Launcher_Custom.git

我做了一些修改,让其可以单独进行编译。 
修改包括:
 1.修改包名,修改包名后安装才不会和系统的冲突
 2.导入编译依赖包。 
  1)framework_intermediates/classes.jar (android的框架类) 
  2)android-common_intermediates/classes.jar (包含com.android.common.Search这个类)
  3)core_intermediates/classes.jar (包含dalvik.system.VMRuntime这个类) 

这三个包放在根目录的sys_lib文件夹中,编译时将三个包,作为user library引用到项目中来。
可以通过配置工程的Build Path来加入, 右键工程名称然后选择
Build Path -> Configure Build Path...->Libraries->Add Library->User Library->User Libraries...>New... 
然后将上面3个依赖的包一个个的加入进来,分别命名为android_framework,android_common,android_core.
进入Order and Export ,调节这3个包的排序,到 Android 包和 Android Dependices包 的前面。

到此,就能编译Launcher进行安装了。

注意:安装最好找一个原生的系统调试,第三方改过的系统,会把launcher请求的一些原生信息改了,这样会导致launcher报错。比如我就遇到过这个问题:

final Cursor c = contentResolver.query(LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);//这个地饭去请求launcher的默认配置,在huawei的系统上面请求这个,得到的c是null


1.壁纸显示

壁纸的显示有2个重要的地方

  1. activity的配置,而且这个配置又有2套方案

     1).AndroidManifest.xml文件里面activity属性里面添加 android:theme="@android:style/Theme.Translucent",并且在Activity的onCreate中添加getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER); 这样得到的activity就有了桌面背景。
     2).activity配置 android:theme="@style/Theme" theme为下面的
<resources>
   <style name="Theme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowShowWallpaper">true</item>
   </style>
</resources>
  这两套方案实际是一样的,都达到在Activity后面显示桌面背景的效果。

  2.页面滑动的同时,滑动桌面背景。

    主要是通过这2个方法来控制的:
    public void setWallpaperOffsetSteps (float xStep, float yStep)
     public void setWallpaperOffsets (IBinder windowToken, float xOffset, float yOffset)

具体调用看Workspace中的
private void updateWallpaperOffset(int scrollRange) {
    IBinder token = getWindowToken();
    if (token != null) {
        mWallpaperManager.setWallpaperOffsetSteps(1.0f / (getChildCount() - 1), 0 );
        mWallpaperManager.setWallpaperOffsets(getWindowToken(),
                Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0);
    }
}

  这个方法会在onTouchEvent事件中调用,也就是说,当手势操作了过后,就调用这个方法来更新壁纸的偏移量,这样就达到了壁纸滚动的效果。

  完了,Launcher的获取壁纸的逻辑就清晰了,首先配置Activity为透明,并配置Activity的后面显示桌面背景(android:windowShowWallpaper = true的作用,这并不是在后面显示桌面哦,是配置activity的背景为桌面背景),当Activity的控件滑动的时候,调用WallpaperManager平移壁纸,就完成壁纸的滚动。

有一哥们,感觉Launcher的刷动效果很不错,于是把这一块抠了出来,得很漂亮,并且加上了桌面背景效果,下载戳这https://github.com/sevenler/ScrollLayout_From_Launcher.git

这个哥们也写了相关Launcher的几篇博客:http://blog.csdn.net/yao_guet/article/details/6572739


2.桌面滑动分析

  桌面的滑动是桌面提供的一个重要操作,滑动是由Workspace提供,继承于ViewGroup,和ViewPager很相识,内部填充的是CellLayout,5个桌面页就有5个CellLayout。
  Workspace中几个重要的代码如下:

   //计算每个子CellLayout的布局大小 

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
	// .....
	// The children are given the same width and height as the scrollLayout
	final int count = getChildCount();
	for (int i = 0; i < count; i++) {
		getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
	}
	scrollTo(mCurScreen * width, 0);
}

//将CellLayout顺序地布局起来

protected void onLayout(boolean changed, int l, int t, int r, int b) {
	//.....
	int childLeft = 0;
	final int childCount = getChildCount();
	
	for (int i=0; i<childCount; i++) {
		final View childView = getChildAt(i);
		if (childView.getVisibility() != View.GONE) {
			final int childWidth = childView.getMeasuredWidth();
			childView.layout(childLeft, 0, 
					childLeft+childWidth, childView.getMeasuredHeight());
			childLeft += childWidth;
		}
	}
	updateWallpaperOffset();
}
    布局完成之后,重点来了,监听手势来滑动。代码集中在下面两个方法中:
 public boolean onInterceptTouchEvent(MotionEvent ev) {
		
		final int action = ev.getAction();
		if ((action == MotionEvent.ACTION_MOVE) && 
				(mTouchState != TOUCH_STATE_REST)) {
			return true;
		}
		
		final float x = ev.getX();
		final float y = ev.getY();
		
		switch (action) {
		//滚动的时候,置滚动状态
		case MotionEvent.ACTION_MOVE:
			final int xDiff = (int)Math.abs(mLastMotionX-x);
			if (xDiff>mTouchSlop) {
				mTouchState = TOUCH_STATE_SCROLLING;
			}
			break;
		//判断Scroller滚动状态设置滚动状态
		case MotionEvent.ACTION_DOWN:
			mLastMotionX = x;
			mLastMotionY = y;
			mTouchState = mScroller.isFinished()? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
			break;
			
		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			//依然置滚动状态
			mTouchState = TOUCH_STATE_REST;
			break;
		}
		
		return mTouchState != TOUCH_STATE_REST;
	}

//接着是处理手势
public boolean onTouchEvent(MotionEvent event) {
	// TODO Auto-generated method stub
	
	//用于计算手势的滑动偏移量
	if (mVelocityTracker == null) {
		mVelocityTracker = VelocityTracker.obtain();
	}
	mVelocityTracker.addMovement(event);
	
	final int action = event.getAction();
	final float x = event.getX();
	final float y = event.getY();
	
	switch (action) {
	.....
	case MotionEvent.ACTION_MOVE://使用scroller来滚动
		int deltaX = (int)(mLastMotionX - x);
		mLastMotionX = x;
        	scrollBy(deltaX, 0);
        	updateWallpaperOffset();
		break;
		
	case MotionEvent.ACTION_UP://根据手势滑动的偏移量来确定是滚动到下一页还是上一页,或者是滚动回当前页
		Log.e(TAG, "event : up");   
		final VelocityTracker velocityTracker = mVelocityTracker;   
		velocityTracker.computeCurrentVelocity(1000);   
		int velocityX = (int) velocityTracker.getXVelocity();   
		Log.e(TAG, "velocityX:"+velocityX); 
		
		if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {   
		    // Fling enough to move left   
		    Log.e(TAG, "snap left");
		    snapToScreen(mCurScreen - 1);   
		} else if (velocityX < -SNAP_VELOCITY   
		        && mCurScreen < getChildCount() - 1) {   
		    // Fling enough to move right   
		    Log.e(TAG, "snap right");
		    snapToScreen(mCurScreen + 1);   
		} else {   
		    snapToDestination();   
		}   
		if (mVelocityTracker != null) {
		    mVelocityTracker.recycle();
		    mVelocityTracker = null;   
		}   
        mTouchState = TOUCH_STATE_REST;   
		break;
	case MotionEvent.ACTION_CANCEL:
		mTouchState = TOUCH_STATE_REST;
		break;
	}
	
	return true;
}


3.应用列表

//使用下面这几句话读取应用列表
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final PackageManager packageManager = mContext.getPackageManager();
List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
//将应用列表排序
Collections.sort(apps, new ResolveInfo.DisplayNameComparator(packageManager));


Launcher分析相关的一些博客

http://www.cnblogs.com/Hwangroid/archive/2011/12/08/2281286.html

http://blog.csdn.net/aomandeshangxiao/article/category/888680

http://blog.csdn.net/stonecao/article/details/6536083





你可能感兴趣的:(分析,Launcher)