XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2020/04/06

使用 Xamarin.Plugin.SharedTransitions 製作出具有跨頁面之共用項目動畫效果

使用 Xamarin.Plugin.SharedTransitions 製作出具有跨頁面之共用項目動畫效果

最近觀看完 .NET Conf: Focus on Xamarin 的 Building Beautiful Apps with Xamarin.Forms 影片,頓時間覺得 Xamarin.Forms 似乎又進化了許多,在這個影片中我看到許多驚豔內容,對於 Xamarin.Plugin.SharedTransitions 這個套件所產生出來的效果,更讓我想要能夠親自來嘗試看看,因此,我先從 Xamarin.Forms-Monkeys 這裡取得許多猴子介紹的紀錄內容,並且將這些內容包裝到練習使用的 NuGet 套件內,接著,實做出如下面影片中的動畫效果。
這個說明專案的原始碼為 xfSharedTransitions

範例專案說明

在這個測試範例專案中,將會使用 Prism Template Pack 建立一個 Xamarin.Forms 的專案,接著要安裝 Xamarin.FFImageLoading.Forms & Xamarin.Plugin.SharedTransitions 這兩個 NuGet 套件;這裡會用到 Xamarin.FFImageLoading.Forms 這個套件,這是因為一開始建立這個測試專案的時候,使用的是 Xamarin.Forms 內的 Image 元件,不過,由於要顯示的猴子圖片是來自於 Internet 上,因此,當要進行頁面切換的時候,對於共用圖片元件的動畫動作,變得不自然與動畫路徑怪怪的,可是,若使用 GiampaoloGabba / Xamarin.Plugin.SharedTransitions 內提供的範例專案,卻可以正常運作,經過了解,發現到該範例專案內使用的貓狗圖片,都是專案內的圖片檔案,不是透過 Internet 方式取得的,所以,就根據該專案的說明內容,嘗試使用 Xamarin.FFImageLoading.Forms 這個元件,讓圖片從 Internet 下載下來,使用本機上快取的圖片檔案,發現到就可以順利運作。
首先,在 [MainPage.xaml] 檔案中,建立底下的 XAML 宣告
在這裡因為會使用到 amarin.FFImageLoading.Forms & Xamarin.Plugin.SharedTransitions 功能,因此,加入了兩個命名空間 sharedTransitions & ffimageloading
而在 ContentPage 內,也使用到兩個附加屬性,用來宣告動畫需要多久的時間,這裡使用 sharedTransitions:SharedTransitionNavigationPage.TransitionDuration="500" 來宣告需要花費 500ms,並且使用 sharedTransitions:SharedTransitionNavigationPage.TransitionSelectedGroup="{Binding SelectedMonkeyId}" 用於宣告點選了哪個集合項目中的紀錄,若僅是做兩個頁面之間的切換,並沒有牽扯到集合項目,例如 ListView,這裡是可以不用使用這個附加屬性哦。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="xfSharedTransitions.Views.MainPage"
             xmlns:behavior="http://prismlibrary.com"
             xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"
             xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
             sharedTransitions:SharedTransitionNavigationPage.TransitionDuration="500"
             sharedTransitions:SharedTransitionNavigationPage.TransitionSelectedGroup="{Binding SelectedMonkeyId}"
             Title="猴仔們">

    <Grid>
        <ListView
            HasUnevenRows="True"
            ItemsSource="{Binding AllMonkey}"
            SelectionMode="None"
            Footer="">
            <ListView.Behaviors>
                <behavior:EventToCommandBehavior
                    EventName="ItemTapped"
                    Command="{Binding MonkeyCommand}"
                    EventArgsParameterPath="Item"/>
            </ListView.Behaviors>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="50"/>
                                <RowDefinition Height="50"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="100"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Label
                                Grid.Row="0" Grid.Column="1"
                                HorizontalOptions="Start" VerticalOptions="End"
                                FontSize="24"
                                Text="{Binding Name}"/>

                            <Label
                                Grid.Row="1" Grid.Column="1"
                                HorizontalOptions="Start" VerticalOptions="Start"
                                FontSize="16"
                                Text="{Binding Location}"/>
                            <ffimageloading:CachedImage HeightRequest="80"
                                                        Grid.Row="0" Grid.RowSpan="2"
                                                        Aspect="AspectFit"
                                                        Source="{Binding ImageUrl}"
                                                        sharedTransitions:Transition.Name="MonkeyImage"
                                                        sharedTransitions:Transition.Group="{Binding Id}"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>

        </ListView>
    </Grid>
</ContentPage>
在這裡因為會使用到 amarin.FFImageLoading.Forms & Xamarin.Plugin.SharedTransitions 功能,因此,加入了兩個命名空間 sharedTransitions & ffimageloading
而在 ContentPage 內,也使用到兩個附加屬性,用來宣告動畫需要多久的時間,這裡使用 sharedTransitions:SharedTransitionNavigationPage.TransitionDuration="500" 來宣告需要花費 500ms,並且使用 sharedTransitions:SharedTransitionNavigationPage.TransitionSelectedGroup="{Binding SelectedMonkeyId}" 用於宣告點選了哪個集合項目中的紀錄,若僅是做兩個頁面之間的切換,並沒有牽扯到集合項目,例如 ListView,這裡是可以不用使用這個附加屬性哦。
在 ItemsTemplate 內,需要使用 sharedTransitions:Transition.Name="MonkeyImage" 這樣的附加屬性宣告,指定兩個頁面都有的共同視覺項目,宣告這裡需要進行動畫的變化動作,而 sharedTransitions:Transition.Group="{Binding Id}" 則是同樣用於集合檢視內才會用到的宣告,這裡將會指定這筆紀錄的 ID 到 Group 屬性內,而這個屬性可以是整數或者是字串,不過,必須具有唯一值特性。
對 MainPage 的 ViewModel,將會使用底下的 C# 程式碼來設計
public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
{
    public event PropertyChangedEventHandler PropertyChanged;

    private readonly INavigationService navigationService;
    public string Title { get; set; }
    public ObservableCollection<Monkey> AllMonkey { get; set; } = new ObservableCollection<Monkey>();
    public DelegateCommand<Monkey> MonkeyCommand { get; set; }
    public int SelectedMonkeyId { get; set; }
    public MainPageViewModel(INavigationService navigationService)
    {
        this.navigationService = navigationService;
        Title = MonkeyData.Monkeys.Count.ToString();
        MonkeyCommand = new DelegateCommand<Monkey>(async x =>
        {
            SelectedMonkeyId = x.Id;

            NavigationParameters para = new NavigationParameters();
            para.Add(nameof(Monkey), x);
            await Task.Delay(100);
            await navigationService.NavigateAsync(nameof(DetailPage), para);
        });
    }

    public void OnNavigatedFrom(INavigationParameters parameters)
    {
    }

    public void OnNavigatedTo(INavigationParameters parameters)
    {
        int idx = 1;
        foreach (var item in MonkeyData.Monkeys)
        {
            AllMonkey.Add(item);
            idx++;
        }
    }

    public void OnNavigatingTo(INavigationParameters parameters)
    {
    }

}
對於點選 ListView 的某個紀錄,將會觸發 MonkeyCommand 這個命令,從這個命令參數中,可以取得使用者所點選的物件值,在這裡,將會把所點選的紀錄物件值,透過導航參數的鍵值 Monkey 傳送到下個頁面去
對於要切換過去的頁面,這裡新增一個 DetailPage.xaml 頁面與 DetailPageViewModel.cs 這兩個檔案,其中,對於頁面部分,將會設計底下的 XAML 宣告內容
從這裡可以很清楚的看到,僅有在圖片檢視的地方,使用到 sharedTransitions:Transition.Name="MonkeyImage" 宣告,這是用來串接兩個頁面共用檢視的宣告方式。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="http://prismlibrary.com"
             prism:ViewModelLocator.AutowireViewModel="True"
             xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
             xmlns:sharedTransitions="clr-namespace:Plugin.SharedTransitions;assembly=Plugin.SharedTransitions"
             x:Class="xfSharedTransitions.Views.DetailPage"
             Title="{Binding Monkey.Name, StringFormat='猴子:{0}'}"
             >

    <Grid>
        <ScrollView>
            <StackLayout Orientation="Vertical">
                <ffimageloading:CachedImage HeightRequest="300" WidthRequest="300"
                                                        Aspect="AspectFit"
                                                        Source="{Binding Monkey.ImageUrl}"
                                                        sharedTransitions:Transition.Name="MonkeyImage"
                                                        />
                <Label
                    HorizontalOptions="Center" VerticalOptions="End"
                    FontSize="24"
                    Text="{Binding Monkey.Name}"/>

                <Label
                    HorizontalOptions="Center" VerticalOptions="Start"
                    FontSize="16"
                    Text="{Binding Monkey.Location}"/>
                <Label
                    HorizontalOptions="Start" VerticalOptions="Start"
                    FontSize="14"
                    Text="{Binding Monkey.Details}"/>
            </StackLayout>
        </ScrollView>
    </Grid>
</ContentPage>




沒有留言:

張貼留言