Android Launcher 入門

Launcher(發射器),就是你經常看到主屏幕吧,其實它也是一個App,它加載着其它app的圖標和名字,並通過意圖打開i它們。

從本博客你可以從認識Launcher並且開發一個簡單的Launcher,在你的模擬器上使用。

注意:

  1. 下面代碼需要自己強烈建議手打,否則你只是複製了一個Demo。
  2. 如果你需要的只是看一下效果的話,請點擊下載,轉到GitHub上下載Demo,並查看。
  3. 在文章底部也有附代碼

一、Launcher

1.什麼是Launcher

安卓系統中的桌面啓動器,安卓系統的桌面UI統稱爲Launcher

2. 定製Launcher

在許多國內手機都定製了自己的Launcher,並不予許用戶使用其它Launcher。

尤其是在智能電視和車載上,都有自己的Launcher。

3.不同Launcher

Launcher也有許多不同版本,這章就不展開講了,只是讓你認識一下Launcher。

具體你可以看這裏

二、開發一個簡單Launcher

開發一個Launcher很簡單,你只需要跟着我寫下面的代碼就可以得到一個自己的Launcher。

1.清單列表

在自己開發的APP的AndroidManifest中添加兩句代碼到自己的Activity裏。

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

 

啓動模擬器,可以使用夜神或者AS中的模擬器,我使用過夜神5.0和AS中模擬器(5.0),都可以。一般國內真機都不行。

運行起來,就是一個Hellowrod,但是一旦返回到主界面,就會彈出詢問使用什麼Launcher。

這裏是因爲系統中有多個Launcher,所以詢問,點擊僅一次。你會發現效果是打開了這個只有HelloWrod的App,其實它已經是你的主屏幕了,接下來我們把它改造的像一點。

2.通過PackageManager獲取應用

 


    private void getApps() {
        PackageManager packageManager = getPackageManager();
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        mMApps = packageManager.queryIntentActivities(intent, 0);
    }

3.建立視圖預覽

簡單點,先創建一個RecycleView,把圖標顯示到上面,並添加點擊事件,跳到個個應用。

在onBindViewHolder中寫獲取App圖標和名字的代碼,和點擊事件的接口回調。


    @Override
    public void onBindViewHolder(@NonNull MyAppsAdapter.ViewHolder viewHolder, int i) {
        ResolveInfo resolveInfo = mMApps.get(i);
        Drawable drawable = resolveInfo.activityInfo.loadIcon(mContext.getPackageManager());
        CharSequence charSequence = resolveInfo.loadLabel(mContext.getPackageManager());
        viewHolder.mAppimg.setImageDrawable(drawable);
        viewHolder.mAppname.setText(charSequence);
        viewHolder.mAppimg.setOnClickListener(v -> {
            mMyAppsAdapterSetOnClickListener.OnClickListener(i);
        });
    }

大概效果就這樣了

此時這個Launcher基本可以使用了,如果你嫌棄它不好看,我們可以加一個簡單的背景。

在Styet裏面添加一個背景

<style name="MyLauncher" parent="android:Theme.Wallpaper">
        <item name="android:windowNoTitle">true</item>
    </style>

在清單裏配置

  <activity
                android:name=".MainActivity"
                android:theme="@style/MyLauncher"
                >

運行一下,效果如下:

如果崩潰了,請更改Activity繼承關係

public class MainActivity extends Activity implements MyAppsAdapter.MyAppsAdapterSetOnClickListener {

三、附代碼:

爲了方便大家查看代碼,在這我附出應用代碼,面去下載代碼的麻煩。

1.manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.example.mylauncher"
        >


    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            tools:ignore="GoogleAppIndexingWarning"
            >
        <activity
                android:name=".MainActivity"
                android:theme="@style/MyLauncher"
                >
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.HOME"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

2.MainActivty

1.MainActivty的代碼

public class MainActivity extends Activity implements MyAppsAdapter.MyAppsAdapterSetOnClickListener {
    private String TAG = "MainActivity";
    private RecyclerView rl;
    private MyAppsAdapter mMyAppsAdapter;
    private List<ResolveInfo> mMApps;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        getApps();
        setData();
    }

    private void setData() {
        if (mMyAppsAdapter == null) {
            mMyAppsAdapter = new MyAppsAdapter(this, mMApps);
        }
        rl.setLayoutManager(new GridLayoutManager(this, 4));
        rl.setAdapter(mMyAppsAdapter);
        mMyAppsAdapter.setMyAppsAdapterSetOnClickListener(this);
    }

    private void getApps() {
        PackageManager packageManager = getPackageManager();
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        mMApps = packageManager.queryIntentActivities(intent, 0);
    }

    private void initView() {
        rl = findViewById(R.id.rl);
    }

    @Override
    public void OnClickListener(int i) {
        ResolveInfo resolveInfo = mMApps.get(i);
        String packageName = resolveInfo.activityInfo.packageName;
        String appName = resolveInfo.activityInfo.name;
        ComponentName componentName = new ComponentName(packageName, appName);
        Intent intent = new Intent();
        intent.setComponent(componentName);
        startActivity(intent);
    }
}

2.MainActivty的佈局

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

<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"
        >

    <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/rl"
            />

</android.support.constraint.ConstraintLayout>

3.MyAppsAdapter

1.MyAppsAdapter代碼

package com.example.mylauncher;

import java.util.List;

import android.content.Context;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

class MyAppsAdapter extends RecyclerView.Adapter<MyAppsAdapter.ViewHolder> {
    private final Context mContext;
    private final List<ResolveInfo> mMApps;

    public MyAppsAdapter(MainActivity context, List<ResolveInfo> mApps) {
        mContext = context;
        mMApps = mApps;
    }

    @NonNull
    @Override
    public MyAppsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view_item, null);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyAppsAdapter.ViewHolder viewHolder, int i) {
        ResolveInfo resolveInfo = mMApps.get(i);
        Drawable drawable = resolveInfo.activityInfo.loadIcon(mContext.getPackageManager());
        CharSequence charSequence = resolveInfo.loadLabel(mContext.getPackageManager());
        viewHolder.mAppimg.setImageDrawable(drawable);
        viewHolder.mAppname.setText(charSequence);
        viewHolder.mAppimg.setOnClickListener(v -> {
            mMyAppsAdapterSetOnClickListener.OnClickListener(i);
        });
    }

    @Override
    public int getItemCount() {
        return mMApps.size();
    }



    public class ViewHolder extends RecyclerView.ViewHolder {

        private final TextView mAppname;
        private final ImageView mAppimg;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            mAppimg = itemView.findViewById(R.id.appimg);
            mAppname = itemView.findViewById(R.id.appname);
        }
    }

    public MyAppsAdapterSetOnClickListener mMyAppsAdapterSetOnClickListener;

    public void setMyAppsAdapterSetOnClickListener(
            MyAppsAdapterSetOnClickListener myAppsAdapterSetOnClickListener) {
        mMyAppsAdapterSetOnClickListener = myAppsAdapterSetOnClickListener;
    }

    interface MyAppsAdapterSetOnClickListener {
        void OnClickListener(int i);
    }
}

xml

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

<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

    <ImageView
            android:id="@+id/appimg"
            android:layout_width="50dp"
            android:layout_height="50dp"
            tools:src="@tools:sample/avatars"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            />

    <TextView
            android:id="@+id/appname"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:text="appname"
            app:layout_constraintTop_toBottomOf="@+id/appimg"
            app:layout_constraintStart_toStartOf="@+id/appimg"
            app:layout_constraintEnd_toEndOf="@+id/appimg"
            />

</android.support.constraint.ConstraintLayout>

3其它

1.style

    <style name="MyLauncher" parent="android:Theme.Wallpaper">
        <item name="android:windowNoTitle">true</item>
    </style>

2.依賴

 implementation 'com.android.support:recyclerview-v7:28.0.0'

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章