創建項目 使用Xamarin開發安卓項目,首先需要安裝VS2017以上版本。因為VS2017以上的版本,可以直接創建Xamarin項目。 另外用Xamarin開發安卓項目,還需要使用Intel的CPU,並且得是雙核以上的CPU,因為調試時,需要使用電腦的虛擬化,奔騰4之類的CPU是不支持虛擬化的。 ...
創建項目
使用Xamarin開發安卓項目,首先需要安裝VS2017以上版本。因為VS2017以上的版本,可以直接創建Xamarin項目。
另外用Xamarin開發安卓項目,還需要使用Intel的CPU,並且得是雙核以上的CPU,因為調試時,需要使用電腦的虛擬化,奔騰4之類的CPU是不支持虛擬化的。
下麵我們創建KibaXamarin_Android項目,如下圖:
點擊確定後,會彈出一個選擇模板的窗體,這裡我們選擇一個空白應用,並且選擇最小安卓版本號為4.4,如下圖:
點擊OK後,項目創建完成,解決方案內容如下圖
解決方案中重要的文件及文件夾如下:
Resources/layout/activity_main.axml:該文件為主頁面。
MainActivity.cs:該文件為主頁面對應的後臺頁面,也我們進行邏輯操作或者調用邏輯操作的地方。
Resources/value/xxx.xml:value文件夾下主要存儲常用的值,類似於我們C#中的const常量。
其他文件夾及文件暫時忽略。
在Resources文件夾里,我們可以發現,沒有存儲圖片的地方,那麼,我們創建一個文件夾drawable用來存儲圖片。
為什麼用drawable存圖片?答案很簡單,因為網上的開源樣式里的圖片大多放在了drawable里,建立一個這樣的文件夾,絕對會減少我們的工作量。
接下來,我們看一下我們的核心文件,MainActivity,代碼如下:
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)] public class MainActivity : AppCompatActivity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // Set our view from the "main" layout resource SetContentView(Resource.Layout.activity_main); } }
首先,我們看第一行的特性,這裡有三個屬性賦值,含義如下:
Label:頁面的標題。
Theme:頁面的樣式。
MainLauncher:是否是主窗體,該屬性在項目只能給一個頁面。
然後,我們可以看到我們的主頁面MainActivity繼承了AppCompatActivity,這裡的AppCompatActivity是一個繼承了Activity的子類,我們暫時先不瞭解它,因為我們即將創建一個繼承Activity的BaseActivity,後續的[Activity]也將繼承BaseActivity。
接下來我們看到了OnCreate方法,這裡我們需要瞭解下Activity的生命周期,OnCreate是Activity的第一個觸發的方法,可以暫時先理解為Activity的構造函數。
OnCreate方法里我們看到了SetContentView(Resource.Layout.activity_main),根據字面我們先簡單的理解該方法為設置內容視圖。
可以看到我們在設置內容視圖的時候,去資源里找了一個頁面;也就是說,在Android中,視圖是倒裝的,現有Activity然後由Activity來控制要導入那個頁面視圖顯示。
為了更好的尋找視圖,我們將視圖名和活動名進行統一,修改頁面的名為MainActivity,然後再重新設置內容視圖。(這裡有個編譯器的BUG,我們改名以後,編譯器並沒有同步,所以我們需要清理一下,再重新生成,如果還不成功,就刪除obj文件夾,再重新生成)
BaseActivity
通過上面的描述,我們初步瞭解了Xamarin的Android項目。
現在我們一起創建一個BaseActivity。
首先我們需要為BaseActivity封裝一些提示信息的方法,讓繼承該類的活動可以更簡單的調用提示。
然後我們封裝尋找資源的方法;在Android項目里是由活動調用視圖,即先有活動後有視圖,所以在活動里找頁面的控制項也是倒裝的,那麼這個尋找控制項的方法就相對代碼會比較多,所以我們簡單封裝一下。
接下來我們在封裝一些跳轉活動、創建服務、非同步調用等基礎方法;BaseActivity代碼如下:
[Activity(Label = "KibaXamarin_Android")] public class BaseActivity : Activity { public void ShowActivity<T>() where T : Activity { Intent intent = new Intent(this, typeof(T)); StartActivity(intent); } public void OpenService<T>() where T : Service { Intent intent = new Intent(this, typeof(T)); StartService(intent); } #region 各種提示信息 public void ShowToast(string msg) { Toast.MakeText(this, msg, ToastLength.Short).Show(); } private AlertDialog dialog; public AlertDialog InitDialog(string msg, Action<AlertDialog> comfirmCallback, Action<AlertDialog> cancelCallback) { AlertDialog cdialog; //構造器 AlertDialog.Builder builder = new AlertDialog.Builder(this); //標題 builder.SetTitle("提示"); //圖標 //builder.SetIcon(android.R.drawable.btn_dialog); //內容 builder.SetMessage(msg); //setPositiveButton(表示按鈕的文本,表示單擊按鈕觸發單擊事件) builder.SetPositiveButton("OK", new EventHandler<DialogClickEventArgs>((s, e) => { if (comfirmCallback != null) { comfirmCallback(dialog); } })); builder.SetNegativeButton("Cancel", new EventHandler<DialogClickEventArgs>((s, e) => { if (cancelCallback != null) { cancelCallback(dialog); } })); //builder.SetNeutralButton("稍後提醒", new EventHandler<DialogClickEventArgs>((s, e) => { })); cdialog = builder.Create();//構建dialog對象 return cdialog; } public void ShowAlert(string msg, Action<AlertDialog> comfirmCallback = null, Action<AlertDialog> cancelCallback = null) { if (comfirmCallback == null) { cancelCallback = (d) => { dialog.Dismiss(); }; } if (cancelCallback == null) { cancelCallback = (d) => { dialog.Dismiss(); }; } dialog = InitDialog(msg, comfirmCallback, cancelCallback); if (dialog != null && !dialog.IsShowing) { dialog.Show(); } } public void NotifyMessage(string message, string title = "消息") { NotificationManager manager = (NotificationManager)GetSystemService(Context.NotificationService); // 在Android進行通知處理,首先需要重系統哪裡獲得通知管理器NotificationManager,它是一個系統Service。 PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, new Intent(this, typeof(MainActivity)), 0); Notification notify1 = new Notification(); notify1.Icon = Resource.Drawable.logo; notify1.TickerText = JaveString("您有新短消息,請註意查收!"); notify1.When = DateTime.Now.ToFileTime(); notify1.SetLatestEventInfo(this, title, message, pendingIntent); notify1.Number = 1; notify1.Flags |= NotificationFlags.AutoCancel; // FLAG_AUTO_CANCEL表明當通知被用戶點擊時,通知將被清除。 // 通過通知管理器來發起通知。如果id不同,則每click,在statu那裡增加一個提示 manager.Notify(1, notify1); } public static Java.Lang.String JaveString(string str) { return new Java.Lang.String("您有新短消息,請註意查收!"); } #endregion #region 尋找資源 public T FindControl<T>(string name) where T : View { return FindViewById<T>(GetCode(name)); } public T FindControl<T>(string name, Action callBack) where T : View { View view = FindViewById<T>(GetCode(name)); view.Click += (s, e) => { callBack(); }; return FindViewById<T>(GetCode(name)); } public int GetCode(string name) { var R = this.Resources; var code = (typeof(Resource.Id)).GetFields().FirstOrDefault(f => f.Name == name).GetValue(R); return (int)code; } #endregion #region 非同步調用 public void AsyncLoad(Action action) { IAsyncResult result = action.BeginInvoke((iar) => { }, null); } public void AsyncLoad(Action action, Action callback) { IAsyncResult result = action.BeginInvoke((iar) => { this.RunOnUiThread(callback); }, null); } public void AsyncLoad<T>(Action<T> action, T para, Action callback) { IAsyncResult result = action.BeginInvoke(para, (iar) => { this.RunOnUiThread(callback); }, null); } public void RunOnUi(Action action) { ((BaseActivity)this).RunOnUiThread(() => { action(); });//回UI線程 } #endregion #region 獲取數據 public void GetRest(string url, Action<JsonValue> callback) { Task.Run(() => { try { HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url)); request.ContentType = "application/json"; request.Method = "GET"; using (WebResponse response = request.GetResponse()) { using (Stream stream = response.GetResponseStream()) { JsonValue jsonDoc = JsonObject.Load(stream); callback(jsonDoc); } } } catch (Exception ex) { Log.Debug("BaseActivity", $"Exception at GetRest" + ex.Message); } }); } #endregion }
視圖MainActivity.axml
Android視圖是有xml語法來編寫的,其中一些語法定義是很奇葩,但也只能去適應,沒有別的辦法。比如Android里定義ID名是這樣的:android:id="@+id/btn_search"。我每次看這個@+id都感覺很奇葩,哈哈。
Xamarin的視圖和Android的視圖是一樣的,所以我們盡可上網找一些資源來使用。
我們先修改視圖代碼如下:
<?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" android:background="#ffffffff"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@drawable/title_background" android:paddingLeft="5dip" android:paddingRight="5dip" android:paddingTop="5dip" android:paddingBottom="5dip" android:gravity="center_vertical"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="2"> <TextView android:textAppearance="?android:textAppearanceMedium" android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="KibaXamarin_Android" android:textColor="#ffffffff" /> <ImageView android:src="@drawable/ic_arrow_down" android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffffff" /> </LinearLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="5"> <ImageButton android:src="@drawable/toolbar_upload_photo_normal" android:layout_gravity="right|center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/btn_weight" /> </FrameLayout> </LinearLayout> <LinearLayout android:gravity="center" android:orientation="horizontal" android:background="@drawable/search_bar_background" android:padding="6.0dip" android:layout_width="fill_parent" android:layout_height="wrap_content"> <Button android:textAppearance="?android:textAppearanceMedium" android:gravity="left|center" android:id="@+id/btn_search" android:layout_width="0.0dip" android:layout_height="wrap_content" android:hint="\u0020Click Me" android:drawableLeft="@drawable/ic_btn_search" android:layout_weight="1.0" /> </LinearLayout> <GridView android:paddingTop="20dip" android:gravity="center" android:id="@+id/my_grid" android:layout_width="fill_parent" android:layout_height="0.0px" android:layout_marginTop="0.0dip" android:horizontalSpacing="10.0dip" android:verticalSpacing="20.0dip" android:stretchMode="columnWidth" android:columnWidth="60.0dip" android:numColumns="3" android:layout_weight="1.0" style="@style/CustomGridView" /> </LinearLayout>
Xamarin的簡單應用
現在,我們的頁面和BaseActivity已經完成,讓我們一起做一些簡單的使用把。
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.MainActivity); Button btn_search = this.FindControl<Button>("btn_search"); btn_search.Click += (s, e) => { this.ShowToast("Click Me"); }; }
如上代碼所示,我們找到了Button-btn_search,併為他創建了單擊事件;看起來還不錯,代碼還算簡潔。
因為BaseActivity里尋找控制項的方法里,還封裝了Click方法,所以我們還可以這樣使用:
Button btn_search = this.FindControl<Button>("btn_search", () => { this.ShowToast("Click Me"); });
Xamarin的調試
Xamarin的調試非常簡單,只要配置好模擬器按F5調試就可以了,因為VS2017集成了Emulator模擬器,所以我們只要運行調試,就會自動幫我們啟動模擬器。
模擬器是配置很簡單,在工具里找到Android—Android設備管理器,如下圖:
然後做一些簡單配置修改,如下圖:
模擬器配置好以後,在調試啟動的選項中,就會增加這個模擬器的選項,如下圖:
接下來就很簡單了,只要直接點擊運行就可以了。
運行結果如下圖:
從圖中我們可以看到,我們的安裝項目已經成功運行了,並且執行了點擊事件。
到此,這個簡單的安卓項目已經創建完成了,下一篇文章,將介紹Xamarin中如何使用安卓控制項。
----------------------------------------------------------------------------------------------------
代碼已經傳到Github上了,歡迎大家下載。
Github地址:https://github.com/kiba518/KibaXamarin_Android
----------------------------------------------------------------------------------------------------
註:此文章為原創,歡迎轉載,請在文章頁面明顯位置給出此文鏈接!
若您覺得這篇文章還不錯,請點擊下右下角的【推薦】,非常感謝!