一、Shortcut 簡介 Shortcut 是 Android 7.1 (API Level 25) 的新特性,類似於蘋果的 3D Touch ,但並不是壓力感應,只是一種長按菜單。Shortcut 是受啟動器限制的,也就是說國內大廠的定製系統大多數是不支持的,那些所謂的可以 pin 在桌面上的應 ...
一、Shortcut 簡介
Shortcut 是 Android 7.1 (API Level 25) 的新特性,類似於蘋果的 3D Touch ,但並不是壓力感應,只是一種長按菜單。Shortcut 是受啟動器限制的,也就是說國內大廠的定製系統大多數是不支持的,那些所謂的可以 pin 在桌面上的應用功能的快捷啟動圖標本質上就是 Shortcut 。
二、Shortcut 在 Xamarin.Forms 中的實現分析
本文討論的是動態 Shortcut 實現。
實現方式無非兩種思路,一種 Native to Forms ,另一種 Forms to Native 。博主最開始考慮的是 Forms to Native ,但沒成功。在設置 ShortcutInfo 時需要一個 Intent ,其中一個構造函數為
public Intent(Context packageContext, Type type);
看著很容易,只要傳入一個 Content 以及 把對應的頁面 typeof 一下即可,但會拋出異常。原因是傳入的 Forms Page 類並不是 Java 的原生類型。查閱 Xamarin.Android 的相關文檔發現,這個 Type 是必須繼承 Activity 類的。那麼,所有的 Forms 頁面均不可傳入,Forms to Native 這條路也就不能走了。
Native to Forms 呢?
既然是需要依賴 Activity 的,那就通過新建一個 Android Activity 去調用 Forms 頁面。
三、代碼實現
下麵新建一個空的 Cross-Platform 項目 ShortcutDemo ,使用 Shared Project 共用代碼。(GitHub:https://github.com/ZhangGaoxing/xamarin-forms-demo/tree/master/ShortcutDemo)
修改 Shared Project
添加兩個 ContentPage 用作測試。
修改 Xamarin.Android
添加兩個活動,ShortcutContainerActivity.cs 與 FormsActivity.cs 。
ShortcutContainerActivity.cs
ShortcutContainerActivity.cs 用來作為展示 Forms 頁面的跳板,因此將其繼承的 Activity 改成 global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity 。同時把 OnCreate 的代碼改成如下所示
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
Intent intent = Intent;
// 獲取傳進來的頁面名稱
string pageName = intent.GetStringExtra("PageName");
var app = new App();
// 設置顯示的頁面
switch (pageName)
{
case "Page1":
app.MainPage = new ShortcutDemo.Views.Page1();
break;
case "Page2":
app.MainPage = new ShortcutDemo.Views.Page2();
break;
default:
break;
}
LoadApplication(app);
}
要註意的是,頂部的 Activity 特性標簽要改動,除了 MainLauncher 要改為 false 以外,其他的全部要和 MainActivity.cs 里的一樣,不然會拋出異常,可能是主題不統一的原因。
[Activity(Label = "ShortcutDemo", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
FormsActivity.cs
FormsActivity.cs 作為正常啟動應用的活動,只是將其從 MainActivity.cs 中剝離開來。代碼如下:
[Activity(Label = "ShortcutDemo", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class FormsActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
}
MainActivity.cs
MainActivity.cs 作為應用程式的入口,由於 Forms 的初始化以及載入已被剝離至 FormsActivity.cs 中,可將 MainActivity.cs 的繼承改為 Activity 類。
在其中添加一個 SetShortcut() 方法用於設置 Shortcut 。首先添加一個 List 用於存放 ShortcutInfo,以備最後動態設置 Shortcut 作為參數傳入。
List<ShortcutInfo> shortcutInfoList = new List<ShortcutInfo>();
接下來實例化一個 Intent 。其中 SetClass 將跳板活動 ShortcutContainerActivity 傳入;SetAction 是必須設置的,要不然報錯都不知道怎麼回事;PutExtra 用於向下一個活動傳遞參數,我們這裡傳入的名稱用於在跳板活動里設置 MainPage 。
Intent page1 = new Intent(); page1.SetClass(this, typeof(ShortcutContainerActivity)); page1.SetAction(Intent.ActionMain); page1.PutExtra("PageName", "Page1");
下麵實例化 ShortcutInfo 。SetRank 為設置排序序號,最多顯示5個 Shortcut ,也就是 0-4 ;SetIcon 為設置圖標;SetShortLabel 與 SetLongLabel 則是設置長名稱與段名稱;SetIntent 則把上一步實例化的 Intent 傳入;最後將其加入 List 。
ShortcutInfo page1Info = new ShortcutInfo.Builder(this, "Page1") .SetRank(0) .SetIcon(Icon.CreateWithResource(this, Resource.Drawable.Page1)) .SetShortLabel("Page1") .SetLongLabel("Page1") .SetIntent(page1) .Build(); shortcutInfoList.Add(page1Info);
最後獲取 ShortcutManager 進行動態設置 Shortcut
ShortcutManager shortcutManager = (ShortcutManager)GetSystemService(Context.ShortcutService); shortcutManager.SetDynamicShortcuts(shortcutInfoList);
因此全部的 MainActivity.cs 的代碼如下:
[Activity(Label = "ShortcutDemo", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetShortcut();
StartActivity(typeof(FormsActivity));
}
private void SetShortcut()
{
List<ShortcutInfo> shortcutInfoList = new List<ShortcutInfo>();
Intent page1 = new Intent();
page1.SetClass(this, typeof(ShortcutContainerActivity));
page1.SetAction(Intent.ActionMain);
page1.PutExtra("PageName", "Page1");
ShortcutInfo page1Info = new ShortcutInfo.Builder(this, "Page1")
.SetRank(0)
.SetIcon(Icon.CreateWithResource(this, Resource.Drawable.Page1))
.SetShortLabel("Page1")
.SetLongLabel("Page1")
.SetIntent(page1)
.Build();
shortcutInfoList.Add(page1Info);
Intent page2 = new Intent();
page2.SetClass(this, typeof(ShortcutContainerActivity));
page2.SetAction(Intent.ActionMain);
page2.PutExtra("PageName", "Page2");
ShortcutInfo page2 = new ShortcutInfo.Builder(this, "Page2")
.SetRank(1)
.SetIcon(Icon.CreateWithResource(this, Resource.Drawable.Page2))
.SetShortLabel("Page2")
.SetLongLabel("Page2")
.SetIntent(page2)
.Build();
shortcutInfoList.Add(page2);
ShortcutManager shortcutManager = (ShortcutManager)GetSystemService(Context.ShortcutService);
shortcutManager.SetDynamicShortcuts(shortcutInfoList);
}
}