C#-Xamarin的Android項目開發(一)——創建項目

来源:https://www.cnblogs.com/kiba/archive/2019/02/14/10361368.html
-Advertisement-
Play Games

創建項目 使用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

----------------------------------------------------------------------------------------------------

註:此文章為原創,歡迎轉載,請在文章頁面明顯位置給出此文鏈接!
若您覺得這篇文章還不錯,請點擊下右下角的推薦】,非常感謝!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 書寫順序: select -> from -> where -> group by -> having -> order by 執行順序: from -> where -> group by -> having -> select -> order by ...
  • 之前因為MySql安全問題,將root@%改為允許特定ip段進行遠程連接,結果有一個介面報The user specified as a definer ('root'@'%') does not exist。 先確定到報錯所涉及的表,然後查看了存儲過程、觸發器、視圖等,最後發現有一個觸發器的def ...
  • mysql壓測mysql自帶就有一個叫mysqlslap的壓力測試工具,通過模擬多個併發客戶端訪問MySQL來執行壓力測試,並且能很好的對比多個存儲引擎在相同環境下的併發壓力性能差別。通過mysqlslap –help可以獲得可用的選項,這裡列一些主要的參數,更詳細的說明參考官方手冊。如果是系統自帶... ...
  • 大家可能使用Navicat Premium時發現很方便,比如複製表或數據結構等,其實這種複製表數據或結構方法就是create table as 和create table like 這種方式實現細心的朋友會問,他們有啥區別呢?。。。廢話不多說,直入正題:比如這裡有張表數據t1: 註意上面有索引: C ...
  • 一、查看所有表的行數select a.name as '表名',b.rows as '表數據行數'from sysobjects a inner join sysindexes bon a.id = b.idwhere a.type = 'u'and b.indid in (0,1)--and a. ...
  • [20190212]刪除tab$記錄的恢復3.txt--//春節前幾天做了刪除tan$記錄的測試,鏈接:http://blog.itpub.net/267265/viewspace-2565245/=> [20190130]刪除tab$記錄的恢復.txthttp://blog.itpub.net/2 ...
  • [20190130]刪除tab$記錄的恢復2.txt--//前面鏈接寫好了腳本,開始測試刪除後的恢復.千萬不要在生產系統做這樣的測試!!--//參考鏈接:http://blog.itpub.net/267265/viewspace-2565245/=>[20190130]刪除tab$記錄的恢復.tx ...
  • [20190130]刪除tab$記錄的恢復.txt--//網上提到許多刪除tab$的案例,主要原因在於沒有從官方正規渠道下載oracle版本,還有一些來自工具裡面帶有一些腳本刪除tab$記錄.--//首先我並不知道許多人的恢復方法,僅僅簡單提到恢複數據字典,我想到既然是刪除,反向的操作就是恢復.也就 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...