我做了一些修改,让其可以单独进行编译。
到此,就能编译Launcher进行安装了。
注意:安装最好找一个原生的系统调试,第三方改过的系统,会把launcher请求的一些原生信息改了,这样会导致launcher报错。比如我就遇到过这个问题:
final Cursor c = contentResolver.query(LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);//这个地饭去请求launcher的默认配置,在huawei的系统上面请求这个,得到的c是null
<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后面显示桌面背景的效果。
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
//计算每个子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; }
//使用下面这几句话读取应用列表 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