2021年11月19日 星期五

for Xanarin.Form : 「處理中」的過場提示訊息

 最近想說MAUI快拍板定案了,那麼Xamarn.Form 這幾年經過各位大神補完下來也應該夠成熟好用了.

真正是「明仔在的窟仔,咱微軟給你挖便便啊」..呃.不是啦,是「明仔在的氣力,咱Xamarin給你傳便便啊」(碼你個B~),所以下個案子,可以考慮用xamarin.form加速開發

我個人最常在畫面會用到的東西是那些過場畫面效果元件,像是「處理中....」這類的東西,所以今天就小小分享一下實作及效果的差異 

(先不說  DisplaySnackBarAsync ,如果你不要自帶動畫的話,這可以直接套用,參考這個影音教學)

先開箱Popup元件,這東西不錯用,日後會非常倚重它,參考以下教學網址
Pass Data From and To Popups with Xamarin Community Toolkit
直接上code

-----ProcessingPopup.xmal--------------------------

<?xml version="1.0" encoding="UTF-8" ?>
<xct:Popup
    xmlns="http://xamarin.com/schemas/2014/forms"

    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
    xmlns:local="clr-namespace:LoraWanApp.Views.PopUp"

    x:TypeArguments="local:PopupResult"
    Size="300,150"
    IsLightDismissEnabled="False"
    x:Class="mycompany.Views.PopUp.ProcessingPopup">
    <StackLayout>

        <Label x:Name="myLabel"  Text="Porcessing......." VerticalOptions="CenterAndExpand"                    HorizontalOptions="CenterAndExpand"/>

    </StackLayout>
</xct:Popup>

----ProcessingPopup.xmal.cs------------------

//Clasable介面沒什麼東西,就只有一個DoClose函數罷了

public class PopupResult {
        public string ReturnData { get; set; }
 }
public partial class ProcessingPopup : Popup<PopupResult>, Closable {
        private PopupResult _result;
        int count = 1;
        bool toLoop = true;
        public ProcessingPopup(PopupResult result) {
            InitializeComponent();
            _result=result;

           //順便學會在form裡用執行緒的技巧
          //UI thread請參考這裡(楓花雪岳)更詳細說明

            Device.BeginInvokeOnMainThread(async () => {
                while(toLoop) {
                    if(count>5)
                        count=1;
                    myLabel.Text="Please Wait"+".....".Substring(0, count);
                    count++;
                    await Task.Delay(500);
                }
                //DoClose();
            });
    }
        public async void DoClose() {
            toLoop=false;
            await Task.Delay(500);
            Dismiss(new PopupResult {
                ReturnData="Close from  Login"
            });
        }
    }

---------------------------------------The caller -- LoginPage.xmal.cs---------------------------
  login按鈕事件:

           //可以用這方式把參數傳給popup   
          var popupResult = new PopupResult {
                ReturnData="Initial data"
            };
            var popup = new ProcessingPopup(popupResult);
            var result = Navigation.ShowPopupAsync(popup) ;  <-- Xamarin.CommunityToolkit.Extensions的popup召喚術!!
            await Task.Delay(10000);//模擬呼叫遠端作業,讓子彈飛一會
            popup.DoClose();
            var r2=await result;
            //日後用到popup做一些比較複雜的對話介面時,就會需要用到傳回技術了
            await DisplayAlert("get msg from Processing", $"return value:{ r2.ReturnData}", "OK");
            await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
------------------------------------------------------------------------------------------------------------
結果: 左為IOS,右為android,可惜的是目前沒有mask選項可以設定,當然你可以在popup裡加上一些小動畫元件,這次我只是用文字做測試,以確定GUI thread可以運作.有必要時再加上frame或許會好一點





「阿你之前用AndroidHud & BTProgressHUD 很好看啊,怎麼不拿來用? 」...好吧,可是AndroidHud是有點東西要加工的,
原本在Xamarin.Android裡的一堆函數會用到的ActivityContext
如「AndroidHUD.AndHUD.Shared.Show(this,"msg",-1,MaskType.Clear)」這裡面的 this是當下的ActivityContext,移植到Xamarin.Form就是Forms.Context,但是!!!!...
Xamarin.Form 2.5之後就不給用Forms.Context,所以要另外加點工
(討論參考這裡)
經上述討論建議,我直接改了Application那裡....
--------------MainApplication.cs----------------------------------

[Application]
public partial class MainApplication : Application, Application.IActivityLifecycleCallbacks {
internal static Context ActivityContext { get; private set; }
public MainApplication(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) { }
public override void OnCreate() {
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
}
public override void OnTerminate() {
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState) {
ActivityContext=activity;
}
public void OnActivityResumed(Activity activity) {
ActivityContext=activity;
}
public void OnActivityStarted(Activity activity) {
ActivityContext=activity;
}
public void OnActivityDestroyed(Activity activity) { }
public void OnActivityPaused(Activity activity) { }
public void OnActivitySaveInstanceState(Activity activity, Bundle outState) { }
public void OnActivityStopped(Activity activity) { }
---------------------------------------------------
------Android實作---------------------------------
    public class DroidHudToaster : IProcessingToast {
        public void dismissProcessAndShowMsg(bool success, string msg) {
            AndHUD.Shared.Dismiss();
            if(success) {
                AndHUD.Shared.ShowSuccessWithStatus(MainApplication.ActivityContext, msg, MaskType.Black, TimeSpan.FromSeconds(3));
            } else {
                AndHUD.Shared.ShowErrorWithStatus(MainApplication.ActivityContext, msg, MaskType.Black, TimeSpan.FromSeconds(3));
            }
        }
        public void showProcessing(string processingMsg = null) {
            AndroidHUD.AndHUD.Shared.Show(MainApplication.ActivityContext,
               (string.IsNullOrWhiteSpace(processingMsg) ? "Loading..." : processingMsg), -1, MaskType.Clear);
        }
    }

------IOS實作----------------------------------
    public class IosToaster : IProcessingToast {
        public void dismissProcessAndShowMsg(bool success, string msg) {
            BTProgressHUD.Dismiss();
            if(success) {
                BTProgressHUD.ShowSuccessWithStatus($"Process Ok:{msg}", MaskType.Black, 3000);
            } else {
                BTProgressHUD.ShowErrorWithStatus($"Errors msg:{msg}", MaskType.Black, 3000);
            }
        }
        public void showProcessing(string processingMsg=null) {
            BTProgressHUD.ShowContinuousProgress((string.IsNullOrWhiteSpace(processingMsg) ? "Loading..." : processingMsg), MaskType.Black);
        }
    }
----------------------------在共同專案裡用DI呼叫---------------
             DependencyService.Get<IProcessingToast>()?.showProcessing("Login now....");
            await Task.Delay(5000);
            DependencyService.Get<IProcessingToast>()?.dismissProcessAndShowMsg(true, "Login OK");
            await Task.Delay(3000);
            await Shell.Current.GoToAsync($"//{nameof(MainFuncsPage)}");
-------------------------------------------------------------------------
結果..... (左為ios,右為android) 果然是DI大法好啊...
-----------------------------------------------------------------

------------------------------------------------------------------------------ 
相信日後MAUI也要更好用好開發了
一起加油吧!!





沒有留言:

張貼留言