Launcher知识点整理(三)

一、增加墙纸

图片放入/packages/apps/Launcher2/res/drawable-mdpi

/packages/apps/Launcher2/res/values-mdpi/wallpapers.xml 

  1. <resources>  
  2.     <string-array name="wallpapers" translatable="false">  
  3.         <item>wallpaper_lake</item>  
  4.         <item>wallpaper_sunset</item>  
  5.         <item>wallpaper_beach</item>  
  6.         <item>wallpaper_snow_leopard</item>  
  7.         <item>wallpaper_path</item>  
  8.         <item>wallpaper_sunrise</item>  
  9.         <item>wallpaper_mountain</item>  
  10.         <item>wallpaper_road</item>  
  11.         <item>wallpaper_jellyfish</item>  
  12.         <item>wallpaper_zanzibar</item>  
  13.         <item>wallpaper_blue</item>  
  14.         <item>wallpaper_grey</item>  
  15.         <item>wallpaper_green</item>  
  16.         <item>wallpaper_pink</item>  
  17.     </string-array>  
  18. </resources>  

设置默认墙纸

frameworks\base\core\res\res\drawable中default_wallpaper.jpg这个是默认的墙纸

二、源代码中设置wallpaper

在launcher.java中

  1. public boolean onCreateOptionsMenu(Menu menu) {  
  2.     if (isWorkspaceLocked()) {  
  3.         return false;  
  4.     }  
  5.     super.onCreateOptionsMenu(menu);  
  6.   
  7.     menu.add(MENU_GROUP_ADD, MENU_ADD, 0, R.string.menu_add)  
  8.             .setIcon(android.R.drawable.ic_menu_add)  
  9.             .setAlphabeticShortcut('A');  
  10.     menu.add(0, MENU_MANAGE_APPS, 0, R.string.menu_manage_apps)  
  11.             .setIcon(android.R.drawable.ic_menu_manage)  
  12.             .setAlphabeticShortcut('M');  
  13.     menu.add(MENU_GROUP_WALLPAPER, MENU_WALLPAPER_SETTINGS, 0, R.string.menu_wallpaper)  
  14.              .setIcon(android.R.drawable.ic_menu_gallery)  
  15.              .setAlphabeticShortcut('W');  
  16.  … …  

点击wallpaper后会调用

  1. public boolean onOptionsItemSelected(MenuItem item) {  
  2.        switch (item.getItemId()) {  
  3.            case MENU_ADD:  
  4.                addItems();  
  5.                return true;  
  6.            case MENU_MANAGE_APPS:  
  7.                manageApps();  
  8.                return true;  
  9.            case MENU_WALLPAPER_SETTINGS:  
  10.                startWallpaper();  
  11.                return true;  
  12.            case MENU_SEARCH:  
  13.                onSearchRequested();  
  14.                return true;  
  15.            case MENU_NOTIFICATIONS:  
  16.                showNotifications();  
  17.                return true;  
  18.        }  
  19.   
  20.        return super.onOptionsItemSelected(item);  
  21.    }  

将进入

  1. private void startWallpaper() {  
  2.     closeAllApps(true);  
  3.     final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);  
  4.     Intent chooser = Intent.createChooser(pickWallpaper,  
  5.             getText(R.string.chooser_wallpaper));  
  6.     startActivityForResult(chooser, REQUEST_PICK_WALLPAPER);  
  7. }  


三、launcher中launcher的搜索框和ProtipWidget(widget修改)

 Launcher2/res/xml/default_workspace.xml

  1. <!--  Middle screen [2] <search>为添加google搜索框;-->  
  2. <search  
  3.     launcher:screen="2"  
  4.     launcher:x="0"  
  5.     launcher:y="0" />  
  6. !--  <appwidget>为添加相应的widget; -->  
  7. <appwidget  
  8.     launcher:packageName="com.android.protips"  
  9.     launcher:className="com.android.protips.ProtipWidget"  
  10.     launcher:screen="2"  
  11.     launcher:x="0"  
  12.     launcher:y="1"  
  13.     launcher:spanX="4"  
  14.     launcher:spanY="1" />  

此xml解析在Launcherprovider.java文件loadFavorites方法中

 

 

四、launcher屏数和默认屏

在launcher.java的Launcher类中有

    static final int SCREEN_COUNT = 5;  //屏数

    static final int DEFAULT_SCREEN = 2;  //默认显示的第几屏(从0屏开始)。

 

修改屏数还需要修改

Launcher2/res/layout-port/Launcher.xml

  1. <!-- The workspace contains 3 screens of cells -->  
  2. <com.android.launcher2.Workspace  
  3.     android:id="@+id/workspace"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:scrollbars="horizontal"  
  7.     android:fadeScrollbars="true"  
  8.     launcher:defaultScreen="2">  
  9.   
  10.     <include android:id="@+id/cell1" layout="@layout/workspace_screen" />  
  11.     <include android:id="@+id/cell2" layout="@layout/workspace_screen" />  
  12.     <include android:id="@+id/cell3" layout="@layout/workspace_screen" />  
  13.     <include android:id="@+id/cell4" layout="@layout/workspace_screen" />  
  14.     <include android:id="@+id/cell5" layout="@layout/workspace_screen" />  
  15.   
  16. </com.android.launcher2.Workspace>  

修改默认屏同时需要修改workspace.java中

  1. public Workspace(Context context, AttributeSet attrs, int defStyle) {  
  2.     super(context, attrs, defStyle);  
  3.   
  4.     … …  
  5.     mDefaultScreen = a.getInt(R.styleable.Workspace_defaultScreen, 1);  
  6.     a.recycle();  
  7.   
  8.     setHapticFeedbackEnabled(false);  
  9.     initWorkspace();  

五、页面标记实现原理

Launcher2/res/drawable/ home_arrows_left.xml

  1. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  2.     <item android:state_pressed="true" android:drawable="@drawable/all_apps_button_pressed" />  
  3.     <item android:state_focused="true" android:state_window_focused="true" android:drawable="@drawable/all_apps_button_focused" />  
  4.     <item android:state_focused="true" android:state_window_focused="false" android:drawable="@drawable/all_apps_button_normal" />  
  5.     <item android:drawable="@drawable/all_apps_button_normal" />  
  6. </selector>  

Launcher2/res/layout-port/Launcher.xml

  1. <ImageView  
  2.     android:id="@+id/previous_screen"  
  3.     android:layout_width="93dip"  
  4.     android:layout_height="@dimen/button_bar_height"  
  5.     android:layout_gravity="bottom|left"  
  6.     android:layout_marginLeft="6dip"  
  7.   
  8.     android:scaleType="center"  
  9.     android:src="@drawable/home_arrows_left"  
  10.       
  11.     android:onClick="previousScreen"    <!—点击事件处理-->  
  12.   
  13.     android:focusable="true"  
  14.     android:clickable="true" />  

在launcher.java中实现

  1. private void setupViews() {  
  2.   
  3. … …  
  4.         mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);  
  5.         mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);  
  6.   
  7.         Drawable previous = mPreviousView.getDrawable();  
  8.         Drawable next = mNextView.getDrawable();  
  9.         mWorkspace.setIndicators(previous, next);  
  10.     … …  
  11. }  

获取这个两旁的图片设置到mCurrentScreen屏幕上

Workspace.java

  1. void setIndicators(Drawable previous, Drawable next) {  
  2.     mPreviousIndicator = previous;  
  3.     mNextIndicator = next;  
  4.     previous.setLevel(mCurrentScreen);  
  5.     next.setLevel(mCurrentScreen);  

在launcher.xml中定义

android:onClick="previousScreen"    <!—点击事件处理-->

在launcher.java中的处理为

  1. @SuppressWarnings({"UnusedDeclaration"})  
  2. public void previousScreen(View v) {  
  3.     if (!isAllAppsVisible()) {  
  4.         mWorkspace.scrollLeft();  
  5.     }  
  6. }  
  7.   
  8. @SuppressWarnings({"UnusedDeclaration"})  
  9. public void nextScreen(View v) {  
  10.     if (!isAllAppsVisible()) {  
  11.         mWorkspace.scrollRight();  
  12.     }  
  13. }  

进入到workspace中

  1. public void scrollLeft() {  
  2.         clearVacantCache();  
  3.         if (mScroller.isFinished()) {  
  4.             if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1);  
  5.         } else {  
  6.             if (mNextScreen > 0) snapToScreen(mNextScreen - 1);              
  7.         }  
  8.     }  
  9.   
  10.     public void scrollRight() {  
  11.         clearVacantCache();  
  12.         if (mScroller.isFinished()) {  
  13.             if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1);  
  14.         } else {  
  15.             if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1);              
  16.         }  
  17.     }  

先判断滑动是否完成,然后跳转到目标屏。

  1. void snapToScreen(int whichScreen) {  
  2.         snapToScreen(whichScreen, 0false);  
  3.     }  
  4.   
  5.     private void snapToScreen(int whichScreen, int velocity, boolean settle) {  
  6.         //if (!mScroller.isFinished()) return;  
  7.   
  8.         whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));  
  9.           
  10.         clearVacantCache();  
  11.         enableChildrenCache(mCurrentScreen, whichScreen);  
  12.   
  13.         mNextScreen = whichScreen;  
  14.   
  15.         mPreviousIndicator.setLevel(mNextScreen);  
  16.         mNextIndicator.setLevel(mNextScreen);  
  17.   
  18.         View focusedChild = getFocusedChild();  
  19.         if (focusedChild != null && whichScreen != mCurrentScreen &&  
  20.                 focusedChild == getChildAt(mCurrentScreen)) {  
  21.             focusedChild.clearFocus();  
  22.         }  
  23.           
  24.         final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen));  
  25.         final int newX = whichScreen * getWidth();  
  26.         final int delta = newX - mScrollX;  
  27.         int duration = (screenDelta + 1) * 100;  
  28.   
  29.         if (!mScroller.isFinished()) {  
  30.             mScroller.abortAnimation();  
  31.         }  
  32.           
  33.         if (settle) {  
  34.             mScrollInterpolator.setDistance(screenDelta);  
  35.         } else {  
  36.             mScrollInterpolator.disableSettle();  
  37.         }  
  38.           
  39.         velocity = Math.abs(velocity);  
  40.         if (velocity > 0) {  
  41.             duration += (duration / (velocity / BASELINE_FLING_VELOCITY))  
  42.                     * FLING_VELOCITY_INFLUENCE;  
  43.         } else {  
  44.             duration += 100;  
  45.         }  
  46.   
  47.         awakenScrollBars(duration);  
  48.         mScroller.startScroll(mScrollX, 0, delta, 0, duration);  
  49.         invalidate();    
  50.     }  

六、左右滑动切换屏幕

在workspace中实现屏幕切换主要重写了以下几个方法:onMeasure()、onLayout()、onInterceptTouchEvent()、onTouchEvent()方法。

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  2.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  3.   
  4.     final int width = MeasureSpec.getSize(widthMeasureSpec);  
  5.     final int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  6.     if (widthMode != MeasureSpec.EXACTLY) {  
  7.         throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");  
  8.     }  
  9.   
  10.     final int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  11.     if (heightMode != MeasureSpec.EXACTLY) {  
  12.         throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");  
  13.     }  
  14.   
  15.     // The children are given the same width and height as the workspace  
  16.     final int count = getChildCount();  
  17.     for (int i = 0; i < count; i++) {  
  18.         getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);  
  19.     }  
  20.   
  21.   
  22.     if (mFirstLayout) {  
  23.         setHorizontalScrollBarEnabled(false);  
  24.         scrollTo(mCurrentScreen * width, 0);  
  25.         setHorizontalScrollBarEnabled(true);  
  26.         updateWallpaperOffset(width * (getChildCount() - 1));  
  27.         mFirstLayout = false;  
  28.     }  
  29. }  


onInterceptTouchEvent()方法和onTouchEvent()主要是来响应手指按下划动时所需要捕获的消息,例如划动的速度,划动的距离等。当手指起来时,根据划动的速度与跨度来判断是向左滑动一页还是向右滑动一页,确保每次用户操作结束之后显示的都是整体的一个子view.

 

在View.java中framework\base\core\java\android\view

将当前视图内容偏移至(x , y)坐标处,即显示(可视)区域位于(x , y)坐标

  1. public void scrollTo(int x, int y) {  
  2.     if (mScrollX != x || mScrollY != y) {  
  3.         int oldX = mScrollX;  
  4.         int oldY = mScrollY;  
  5.         mScrollX = x;  
  6.         mScrollY = y;  
  7.         onScrollChanged(mScrollX, mScrollY, oldX, oldY);  
  8.         if (!awakenScrollBars()) {  
  9.             invalidate();  
  10.         }  
  11.     }  
  12. }  

在当前视图内容继续偏移(x , y)个单位,显示(可视)区域也跟着偏移(x,y)个单位

  1. public void scrollBy(int x, int y) {  
  2.     scrollTo(mScrollX + x, mScrollY + y);  
  3. }  
mScrollX 与 mScrollY 代表我们当前偏移的位置 , 在当前位置继续偏移(x ,y)个单位 


七、获取应用列表(相当于mainmenu)

在launcher.java中

Launcher 布局文件初始化方法中

  1. private void setupViews() {  
  2. … …   
  3. mHandleView = (HandleView) findViewById(R.id.all_apps_button);  
  4. mHandleView.setLauncher(this);  
  5. mHandleView.setOnClickListener(this);  
  6. mHandleView.setOnLongClickListener(this);  
  7. … …  
  8. }  

点击中间button

  1. public void onClick(View v) {  
  2.     Object tag = v.getTag();  
  3.     if (tag instanceof ShortcutInfo) {  
  4. …  
  5.     } else if (tag instanceof FolderInfo) {  
  6.         handleFolderClick((FolderInfo) tag);  
  7.     } else if (v == mHandleView) {  
  8.         if (isAllAppsVisible()) {  
  9.             closeAllApps(true);  
  10.         } else {  
  11.             showAllApps(true);  
  12.         }  
  13.     }  

进入到showAllApps()方法

  1. void showAllApps(boolean animated) {  
  2.     mAllAppsGrid.zoom(1.0f, animated);  
  3.   
  4.     ((View) mAllAppsGrid).setFocusable(true);  
  5.     ((View) mAllAppsGrid).requestFocus();  
  6.       
  7.     // TODO: fade these two too  
  8.     mDeleteZone.setVisibility(View.GONE);  
  9. }  

在上面使用到了mAllAppsGrid

 privateAllAppsView mAllAppsGrid; //声明

在setupViews()方法中

  1. private void setupViews() {  
  2. … …  
  3.         mAllAppsGrid = (AllAppsView)dragLayer.findViewById(R.id.all_apps_view);  
  4.         mAllAppsGrid.setLauncher(this);  
  5.         mAllAppsGrid.setDragController(dragController);  
  6.         ((View) mAllAppsGrid).setWillNotDraw(false); // We don't want a hole punched in our window.  
  7.         // Manage focusability manually since this thing is always visible  
  8.         ((View) mAllAppsGrid).setFocusable(false);  
  9.         … …  
  10. }  

all_apps_view是在all_app_2d.xml中定义

位于res/layout-port中

故找到AllApps2D.java可以找到addApps,removeApps,zoom这几个方法。

  1. public void zoom(float zoom, boolean animate) {  
  2.       Log.d(TAG, "zooming " + ((zoom == 1.0) ? "open" : "closed"));  
  3.     cancelLongPress();  
  4.   
  5.     mZoom = zoom;  
  6.   
  7.     if (isVisible()) {  
  8.         getParent().bringChildToFront(this);  
  9.         setVisibility(View.VISIBLE);  
  10.         mGrid.setAdapter(mAppsAdapter);  
  11.         if (animate) {  
  12.             startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_in));  
  13.         } else {  
  14.             onAnimationEnd();  
  15.         }  
  16.     } else {  
  17.         if (animate) {  
  18.             startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.all_apps_2d_fade_out));  
  19.         } else {  
  20.             onAnimationEnd();  
  21.         }  
  22.     }  
  23. }  

在zoom()方法里面有mGrid.setAdapter(mAppsAdapter),在构造方法中,给adapter已经赋值。

  1. public AllApps2D(Context context, AttributeSet attrs) {  
  2.     super(context, attrs);  
  3.     setVisibility(View.GONE);  
  4.     setSoundEffectsEnabled(false);  
  5.   
  6.     mAppsAdapter = new AppsAdapter(getContext(), mAllAppsList);  
  7.     mAppsAdapter.setNotifyOnChange(false);  
  8. }  

在launcher.java函数中

  1. private void loadHotseats() {  
  2. … …   
  3. PackageManager pm = getPackageManager();  
  4. … …  
  5. ResolveInfo bestMatch = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);  
  6. List<ResolveInfo> allMatches = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);  
  7. … …  
  8. }  

如此获取了应用列表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值