手把手教你定制android桌面

来源:互联网 发布:淘宝实体店是什么意思 编辑:程序博客网 时间:2024/06/06 01:12

launcher,也就是android的桌面应用程序。下图是android2.3launcher应用程序:

  
 

接下来我们要开发一个自己的launcher,使其替代系统的默认launcher
怎样使我们的应用程序成为一个launcher

下面我们就新建一个叫做MyHome的工程,具体步骤略。创建完工程后整个目录结构如下图:
 

现在我们的AndroidManifest.xml文件这样的:

<?xml version="1.0"encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="org.bangchui.myhome"

      android:versionCode="1"

      android:versionName="1.0">

 

 

    <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">

        <activityandroid:name=".MyHome"

                  android:label="@string/app_name">

            <intent-filter>

                <actionandroid:name="android.intent.action.MAIN" />

                <categoryandroid:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

 

    </application>

</manifest>

请注意<intent-filter>
</intent-filter>里面的内容。
下面我们在其中添加上以下两行:

?

1

2

<category android:name="android.intent.category.HOME" />

<category android:name="android.intent.category.DEFAULT" />

此时AndroidManifest.xml文件是这样:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="org.bangchui.myhome"

      android:versionCode="1"

      android:versionName="1.0">

 

 

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".MyHome"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

                <category android:name="android.intent.category.HOME" />

                <category android:name="android.intent.category.DEFAULT" />

            </intent-filter>

        </activity>

 

    </application>

</manifest>

此时运行程序,我们看不到任何特别之处。当按下home键时(模拟器上按下home会调出桌面应用),程序如图:  

我们看到了,我们开发的Myhome跟Launcher出现在了一起。 
重启模拟器,我们看到我们自己的程序已经可以作为home来运行了。
ok。 第一步完成了:把我们的应用程序作为home。

总结一下:要把我们的应用程序作为home,只需要在AndroidManifest.xml中添加:
 <category android:name="android.intent.category.HOME" />
 <category android:name="android.intent.category.DEFAULT"/>

 

 

 

 

 

 

 

android手把手教你开发launcher (二)

第二课:列出安装的应用程序


预备知识: GridView的使用 \ 改写BaseAdapter 

列出已经安装的应用程序是作为launcher比不可少的功能。下面我们就讲解怎样将应用程序列出来。程序运行后的样子如下:
 


一. 修改main.xml,在其中添加一个GridView用来显示应用程序列表。
修改后如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical" android:layout_width="fill_parent"

    android:layout_height="fill_parent">

     

    <GridView android:layout_width="match_parent"

        android:id="@+id/apps_list"

        android:numColumns="4"

        android:layout_height="wrap_content">

    </GridView>

 

</LinearLayout>



二 . 通过PackageManager的api 查询已经安装的apk
我们写一个叫做loadApps的方法将活得的应用程序列表放到private List<ResolveInfo> mApps; 中,如下:

?

1

2

3

4

5

6

private void loadApps() {

        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);

        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

 

        mApps = getPackageManager().queryIntentActivities(mainIntent, 0);

    }



三. 实现用于显示Gridview的Adapter,使其显示获得的应用程序列表



直接上代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

public class AppsAdapter extends BaseAdapter {

        public AppsAdapter() {

        }

 

 

        public View getView(int position, View convertView, ViewGroup parent) {

            ImageView i;

 

 

            if (convertView == null) {

                i = new ImageView(MyHome.this);

                i.setScaleType(ImageView.ScaleType.FIT_CENTER);

                i.setLayoutParams(new GridView.LayoutParams(50, 50));

            } else {

                i = (ImageView) convertView;

            }

 

 

            ResolveInfo info = mApps.get(position);

            i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));

 

 

            return i;

        }

 

 

 

 

        public final int getCount() {

            return mApps.size();

        }

 

 

        public final Object getItem(int position) {

            return mApps.get(position);

        }

 

 

        public final long getItemId(int position) {

            return position;

        }

    }



最后整个Activity的代码如下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

package org.bangchui.myhome;

 

 

import java.util.List;

 

 

import android.app.Activity;

import android.content.Intent;

import android.content.pm.ResolveInfo;

import android.os.Bundle;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.GridView;

import android.widget.ImageView;

 

 

public class MyHome extends Activity {

      GridView mGrid;

     

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

         

        loadApps();

        setContentView(R.layout.main);

        mGrid = (GridView) findViewById(R.id.apps_list);

        mGrid.setAdapter(new AppsAdapter());

    }

     

     

    private List<ResolveInfo> mApps;

 

 

    private void loadApps() {

        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);

        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

 

 

        mApps = getPackageManager().queryIntentActivities(mainIntent, 0);

    }

 

 

    public class AppsAdapter extends BaseAdapter {

        public AppsAdapter() {

        }

 

 

        public View getView(int position, View convertView, ViewGroup parent) {

            ImageView i;

 

 

            if (convertView == null) {

                i = new ImageView(MyHome.this);

                i.setScaleType(ImageView.ScaleType.FIT_CENTER);

                i.setLayoutParams(new GridView.LayoutParams(50, 50));

            } else {

                i = (ImageView) convertView;

            }

 

 

            ResolveInfo info = mApps.get(position);

            i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));

 

 

            return i;

        }

 

 

 

 

        public final int getCount() {

            return mApps.size();

        }

 

 

        public final Object getItem(int position) {

            return mApps.get(position);

        }

 

 

        public final long getItemId(int position) {

            return position;

        }

    }

}

第三课 启动安装的应用程序

1. 监听GridView的onItemClick事件
设置一个监听器是为了当gridView的某项被点击时,会有一个回调函数通知我们。
我们调用mGrid.setOnItemClickListener(listener); 设置一个监听器
mGrid.setOnItemClickListener(listener)中的listener是一个接口,其类型为:android.widget.AdapterView.OnItemClickListener,如下图所示:
 

下面我们new一个android.widget.AdapterView.OnItemClickListener类型的对象作为参数。我们直接使用eclipde的自动补全功能来完成OnItemClickListener的定义:

?

1

2

3

4

5

private OnItemClickListener listener = new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> parent, View view, int position,long id) {

}

};



接口OnItemClickListener 中有一个方法叫做onItemClick,我们实现它即可。下面我对onItemClick的几个参数略作说明:
parent     略
view          被点击的view
position     被点击项的位置
id             被点击项的id

2.启动被点击应用的activity

一般来讲,我们根据position即可知道被点击的项目是哪一项了。现在我们根据被点击的项目,取出对应的应用程序数据(主要是其中的主activity),然后启动activity。用下面代码实现:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@Override

        public void onItemClick(AdapterView<?> parent, View view, int position,long id) {

            ResolveInfo info = mApps.get(position);

             

            //该应用的包名

            String pkg = info.activityInfo.packageName;

            //应用的主activity类

            String cls = info.activityInfo.name;

             

            ComponentName componet = new ComponentName(pkg, cls);

             

            Intent i = new Intent();

            i.setComponent(componet);

            startActivity(i);

        }



例如,我们点击计算器时,启动了计算器,如下图:
 


现在整个类代码如下:

复制代码

  1. package org.bangchui.myhome;
  2.  
  3. import java.util.List;
  4.  
  5. import android.app.Activity;
  6. import android.content.ComponentName;
  7. import android.content.Intent;
  8. import android.content.pm.ResolveInfo;
  9. import android.os.Bundle;
  10. import android.view.View;
  11. import android.view.ViewGroup;
  12. import android.widget.AdapterView;
  13. import android.widget.BaseAdapter;
  14. import android.widget.GridView;
  15. import android.widget.ImageView;
  16. import android.widget.AdapterView.OnItemClickListener;
  17.  
  18. public class MyHome extends Activity {
  19.     private List<ResolveInfo> mApps;
  20.     GridView mGrid;
  21.     private OnItemClickListener listener = new OnItemClickListener() {
  22.         @Override
  23.         public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
  24.             ResolveInfo info = mApps.get(position);
  25.             
  26.             //该应用的包名
  27.             String pkg = info.activityInfo.packageName;
  28.             //应用的主activity类
  29.             String cls = info.activityInfo.name;
  30.             
  31.             ComponentName componet = new ComponentName(pkg, cls);
  32.             
  33.             Intent i = new Intent();
  34.             i.setComponent(componet);
  35.             startActivity(i);
  36.         }
  37.  
  38.     };
  39.  
  40.     /** Called when the activity is first created. */
  41.     @Override
  42.     public void onCreate(Bundle savedInstanceState) {
  43.         super.onCreate(savedInstanceState);
  44.  
  45.         loadApps();
  46.         setContentView(R.layout.main);
  47.         mGrid = (GridView) findViewById(R.id.apps_list);
  48.         mGrid.setAdapter(new AppsAdapter());
  49.  
  50.         mGrid.setOnItemClickListener(listener);
  51.     }
  52.  
  53.  
  54.     private void loadApps() {
  55.         Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
  56.         mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
  57.  
  58.         mApps = getPackageManager().queryIntentActivities(mainIntent, 0);
  59.     }
  60.  
  61.     public class AppsAdapter extends BaseAdapter {
  62.         public AppsAdapter() {
  63.         }
  64.  
  65.         public View getView(int position, View convertView, ViewGroup parent) {
  66.             ImageView i;
  67.  
  68.             if (convertView == null) {
  69.                 i = new ImageView(MyHome.this);
  70.                 i.setScaleType(ImageView.ScaleType.FIT_CENTER);
  71.                 i.setLayoutParams(new GridView.LayoutParams(50, 50));
  72.             } else {
  73.                 i = (ImageView) convertView;
  74.             }
  75.  
  76.             ResolveInfo info = mApps.get(position);
  77.             i.setImageDrawable(info.activityInfo.loadIcon(getPackageManager()));
  78.  
  79.             return i;
  80.         }
  81.  
  82.         public final int getCount() {
  83.             return mApps.size();
  84.         }
  85.  
  86.         public final Object getItem(int position) {
  87.             return mApps.get(position);
  88.         }
  89.  
  90.         public final long getItemId(int position) {
  91.             return position;
  92.         }
  93.     }
  94. }

 

 

 

 

 

 

 

 

 

 

 

 

 

我们在前面的课程中已经列出了安装的应用程序,并且点击后可以启动应用程序了!
下面我们来研究如何显示widget。
源代码: 附件出售:TestWidget.7z 

我们要达到这样的效果:点击“add widget” 后弹出widget列表,之后选择一个widget后显示在界面上,如下:

 




第四课:显示widget


1. 获取widget信息


获取widget其实非常简单,我们只需要发送一个请求到系统,系统就会打开widget的列表,然后我们选择一个即可。代码如下:

?

1

2

3

4

5

6

7

void addWidget() {

        int appWidgetId = mAppWidgetHost.allocateAppWidgetId();

        Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);

        pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

        // start the pick activity

        startActivityForResult(pickIntent, [b]REQUEST_PICK_APPWIDGET[/b]);

    }





2. 添加widget的view到layout中
当选择一个widget后会通过onActivityResult 通知到activity,widget的信息被包含在 Intent data中,详情看代码注释

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

   @Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        // The pattern used here is that a user PICKs a specific application,

        // which, depending on the target, might need to CREATE the actual

        // target.

 

        // For example, the user would PICK_SHORTCUT for "Music playlist", and

        // we

        // launch over to the Music app to actually CREATE_SHORTCUT.

 

        if (resultCode == RESULT_OK) {

            switch (requestCode) {

            case REQUEST_PICK_APPWIDGET:

                addAppWidget(data);

                break;

            case REQUEST_CREATE_APPWIDGET:

                completeAddAppWidget(data);

                break;

 

            }

        }

    }

 

    void addAppWidget(Intent data) {

        // TODO: catch bad widget exception when sent

        int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,

                -1);

        AppWidgetProviderInfo appWidget = mAppWidgetManager

                .getAppWidgetInfo(appWidgetId);

 

        //widget 包含设置信息不为空,则启动widget的设置界面

        if (appWidget.configure != null) {

            // Launch over to configure widget, if needed

            Intent intent = new Intent(

                    AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);

            intent.setComponent(appWidget.configure);

            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

 

            startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);

        } else {

        //    widget 包含设置信息为空,直接添加widget到layout中

            // Otherwise just add it

            onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);

        }

    }

 

    void startActivityForResultSafely(Intent intent, int requestCode) {

        try {

            startActivityForResult(intent, requestCode);

        } catch (ActivityNotFoundException e) {

            Toast.makeText(this, "activity_not_found", Toast.LENGTH_SHORT)

                    .show();

        } catch (SecurityException e) {

            Toast.makeText(this, "activity_not_found", Toast.LENGTH_SHORT)

                    .show();

        }

    }

 

    /**

     * 添加widget信息到layout中

     * @param data 包含了widget的信息

     */

    private void completeAddAppWidget(Intent data) {

        Bundle extras = data.getExtras();

        int appWidgetId = extras

                .getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);

 

        Log.d(TAG, "dumping extras content=" + extras.toString());

 

        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager

                .getAppWidgetInfo(appWidgetId);

 

        // Perform actual inflation because we're live

        synchronized (mLock) {

             

            //获取显示widget的view

            mHostView = mAppWidgetHost.createView(this, appWidgetId,

                    appWidgetInfo);

            mHostView.setAppWidget(appWidgetId, appWidgetInfo);

 

            //将获取的view添加早layout中

            LayoutParams lp = new LinearLayout.LayoutParams(

                    appWidgetInfo.minWidth, appWidgetInfo.minHeight);

            mainLayout.addView(mHostView, lp);

 

            mHostView.requestLayout();

        }

 

    }

显示壁纸也是launcher必不可少的功能,下面我们看看如何让我们开发的launcher来显示壁纸。


新建一个叫做ShowWallpaper的工程,具体步骤略。

一. 显示壁纸
要在我们的activity里显示一个壁纸非常简单(包括动态壁纸也如此),我们只需要定义一个theme使其继承自android:Theme.Wallpaper,然后在activity中使用这个theme就ok了。
在res/valuse下面增加一个xml文件,其名称为styles.xml ,内容如下:

?

1

2

3

4

5

6

<resources>

    <style name="Theme" parent="android:Theme.Wallpaper">

        <!-- windowNoTitle设置为true,去掉标题栏 -->

        <item name="android:windowNoTitle">true</item>

    </style>

</resources>


此时整个工程的结果如下:

 

下面在AndroidManifest.xml中使用这个theme,如下图所示:
 


xml代码如下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.test"

      android:versionCode="1"

      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".ShowWallpaper"

                     android:theme="@style/Theme"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

 

 

    </application>

</manifest>




好了,运行程序,可以看到壁纸的显示效果了:(显示的是预设置的动态壁纸:星系)

 

 

 

设置壁纸


用代码设置壁纸也是非常地简单的事,我们只需要向系统发送一个“设置请求”就足够了,其它的事情系统处理。


用下面代码表示:

?

1

2

3

4

5

6

7

public void onSetWallpaper(View view) {

                        //生成一个设置壁纸的请求

             final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);

                Intent chooser = Intent.createChooser(pickWallpaper,"chooser_wallpaper");

                //发送设置壁纸的请求

                startActivity(chooser);

    }





为了调用上面这段代码,我们在xml中添加一个button,并设置回调函数,如下图:
 

最后运行代码,步骤如下图所示:
 


设置壁纸后:
 

 

 

 

 

 

 

 

原创粉丝点击