给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"

Windows Phone 是那个1%, 我也是那个1%, 不喜勿喷.
WP 向来给 android / ios 的粉们一个最直观的印象: 丑.
其实"丑"这个东西会一直下去,而且是个解不开的死循环.

 

WP 下, 做的华丽的, 目前我用过的只有少数几个, 网易云音乐 和 智机社区, 做的漂亮而且流畅, 其它的只能用渣渣来形容.

给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"_第1张图片给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"_第2张图片给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"_第3张图片给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"_第4张图片

 

Xamarin.Form 的 APP 在 Android 和 IOS 下默认都会有一个"头", 用于显示页面名称和导航按钮.
在 WP 下却没有, 像这样:

给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"_第5张图片

 

 

Xamarin.Form 在 WP 的 MainPage.xaml.cs 中这样定义:

public partial class MainPage : FormsApplicationPage{
...
        public MainPage() {
            InitializeComponent();
            SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;

            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new LBC.Mobi.App());
        }

 

FormsApplicationPage.LoadApplication 方法的定义:

 1     protected void LoadApplication(Xamarin.Forms.Application application)
 2     {
 3       Xamarin.Forms.Application.Current = application;
 4       application.PropertyChanged += new PropertyChangedEventHandler(this.ApplicationOnPropertyChanged);
 5       this.application = application;
 6       application.SendStart();
 7       this.SetMainPage();
 8     }
 9 
10 
11     private void SetMainPage()
12     {
13       if (this.platform == null)
14         this.platform = new Platform((PhoneApplicationPage) this);
15       this.platform.SetPage(this.application.MainPage);
16       if (this.Content == this.platform)
17         return;
18       this.Content = (UIElement) this.platform;
19     }

这样一个调用链:

LoadApplication -> SetMainPage -> 直接给整个页面的 Content 赋值.

所以, 无论你在 MainPage.xaml 中写什么内容, 最终都是无法显示的.

 

为了达成目的, 我们需要修改 SetMainPage 方法 , 使 this.platform 只作为 MainPage  的一部分, 而不是整个 Content.

但是反编译一下, 可以看到 Xamarin.Form 的封装很蛋疼, 很多都是 internal , private, 不带 virtual, 所以, 通过正常手段是无法对 Xamarin.Form 进行扩展的.

给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"_第6张图片

还好, Xamarin 对反射支持的很到位, 无法正常通过继承/重写来实现, 我们照样可以用反射来完成它.

 

1, 在 MainPage.xaml.cs 中新增方法 LoadApplication:

 1         new protected void LoadApplication(Xamarin.Forms.Application application) {
 2             //Xamarin.Forms.Application.Current = application;
 3             typeof(Xamarin.Forms.Application).GetProperty("Current", BindingFlags.Static | BindingFlags.Public)
 4                 .SetValue(Xamarin.Forms.Application.Current, application);
 5 
 6 
 7             application.PropertyChanged += new PropertyChangedEventHandler(this.ApplicationOnPropertyChanged);
 8             typeof(FormsApplicationPage).GetField("application", BindingFlags.NonPublic | BindingFlags.Instance)
 9                 .SetValue(this, application);
10 
11             //application.SendStart();
12             application.GetType().GetMethod("SendStart", BindingFlags.NonPublic | BindingFlags.Instance)
13                 .Invoke(application, null);
14 
15             this.SetMainPage();
16 
17             var mp = (Xamarin.Forms.NavigationPage)application.MainPage;
18             mp.PropertyChanged += MainPage_PropertyChanged;
19             this.Title = mp.Title;
20         }

 

为了能显示当前页的标题, 我在上面的方法中加了一段(红色标注), 实际中, 你的 application.MainPage 可能不是 NavigationPage,  需要自行修改.

 

2, 

1         void MainPage_PropertyChanged(object sender, PropertyChangedEventArgs e) {
2             if (e.PropertyName.Equals("CurrentPage")) {
3                 this.Title = ((Xamarin.Forms.NavigationPage)sender).CurrentPage.Title;
4                 this.PropertyChanged(this, new PropertyChangedEventArgs("Title"));
5             }
6         }

 

 

3, 在 MainPage.xaml.cs 中添加 SetMainPage :

 1         private void SetMainPage() {
 2             if (this.Platform == null) {
 3                 this.Platform = new Platform((PhoneApplicationPage)this);
 4             }
 5 
 6             this.Platform.SetPage(Xamarin.Forms.Application.Current.MainPage);
 7             if (this.mainBody.Content != null && this.mainBody.Content.Equals(this.Platform))
 8                 return;
 9             this.mainBody.Content = (UIElement)this.Platform;
10         }

 

 

4, 修改 MainPage.xaml 

 1 <winPhone:FormsApplicationPage
 2     x:Class="Discuz.WinPhone.MainPage"
 3     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 4     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 5     xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
 6     xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
 7     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 8     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 9     xmlns:winPhone="clr-namespace:Xamarin.Forms.Platform.WinPhone;assembly=Xamarin.Forms.Platform.WP8"
10     xmlns:local="clr-namespace:Discuz.WinPhone"
11     mc:Ignorable="d"
12     FontFamily="{StaticResource PhoneFontFamilyNormal}"
13     FontSize="{StaticResource PhoneFontSizeNormal}"
14     Foreground="{StaticResource PhoneForegroundBrush}"
15     SupportedOrientations="Portrait" Orientation="Portrait"
16     shell:SystemTray.IsVisible="True"
17     shell:SystemTray.Opacity="0"
18     Background="#1e5263"
19     >
20     <!--shell:SystemTray.BackgroundColor="#2ba9d3"-->
21 
22     <Grid>
23         <Grid.RowDefinitions>
24             <RowDefinition Height="15" /><!-- for SystemTray -->
25             <RowDefinition Height="auto" />
26             <RowDefinition Height="*" />
27         </Grid.RowDefinitions>
28         <local:TilePanel TileWidth="5" TileHeight="5" Height="65" Grid.Row="0" Grid.RowSpan="2">
29             <local:TilePanel.Image>
30                 <ImageBrush ImageSource="texture.png" />
31             </local:TilePanel.Image>
32         </local:TilePanel>
33         <StackPanel Orientation="Horizontal" Margin="10,0" Grid.Row="1" VerticalAlignment="Center">
34             <Image Source="icon.png" Width="40" Height="40" Margin="0,0,10,0" />
35             <TextBlock Text="{Binding Title}" VerticalAlignment="Center" />
36         </StackPanel>
37 
38         <ContentPresenter x:Name="mainBody" Grid.Row="2" />
39     </Grid>
40 
41 </winPhone:FormsApplicationPage>

 

 

 好啦, 一个带标题的 XF For WP 的 APP 改造完了.

最终效果:

给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"_第7张图片给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头"_第8张图片

 

 

具体参见:

https://github.com/gruan01/Discuz.Mobi/tree/master/Discuz/Discuz.WinPhone

 

 

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

OK, 完

 

你可能感兴趣的:(给 Xamarin.Form For Windows Phone APP 加个漂亮的 "头")