笔记 | Xamarin

2022-04-01 16:47:22 浏览数 (1)

引言

文件读写

参考:

  • 使用 Xamarin.Android 对外部存储进行的文件访问 - Xamarin | Microsoft Docs
  • Xamarin 中的文件系统访问 - Xamarin | Microsoft Docs
  • 关于xamarin.forms Android创建文件与写文件 (ftp) - 懒猫口米 - 博客园

外部读写

应用可以在外部存储上保留两种不同类型的文件:

  • 专用 文件 – 专用文件是特定于应用程序的文件(但仍然全局可读且全局可写)。 Android 期望专用文件存储在外部存储上的特定目录中。 尽管这些文件称为“专用”,但它们仍然可见,并且可由设备上的其他应用访问,Android 并没有对它们提供任何特殊保护。
代码语言:javascript复制
// 专用外部存储目录
// /storage/emulated/0/Android/data/com.companyname.app/files/
Android.Content.Context.GetExternalFilesDir(string type)
  • 公共 文件 – 这些文件不被视为特定于应用程序,可自由共享。
代码语言:javascript复制
// 主外部存储目录
// /storage/emulated/0/
Android.OS.Environment.ExternalStorageDirectory

Android 将外部存储视为危险权限,这通常要求用户授予其访问资源的权限。 用户可以随时撤销此权限。 这意味着在进行任何文件访问之前都应执行运行时权限请求。 应用会被自动授予读取和写入其自己的专用文件的权限。 在用户授予了权限之后,应用可以读取和写入属于其他应用的专用文件。

代码语言:javascript复制
//global::Android.OS.Environment.ExternalStorageDirectory.AbsolutePath :得到安卓的根目录
//Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)::得到安卓data目录
var path = global::Android.OS.Environment.ExternalStorageDirectory.AbsolutePath   Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

// 创建文件
System.IO.Directory.CreateDirectory(path);

外部存储权限

所有 Android 应用都必须在 AndroidManifest.xml 中为外部存储声明两个权限之一。

若要标识权限,必须将以下两个 uses-permission 元素之一添加到 AndroidManifest.xml:

代码语言:javascript复制
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

注意:下面有误

如上,在安卓项目里有个Properties的文件下有个AndroidManifest.xml的文件。在

代码语言:javascript复制
<application android:label="cardionNet2.Android"></application> 

下加

这个目测有误,直接加进去就是了,不需要放在这个;里

代码语言:javascript复制
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.demoapp" android:installLocation="auto">
	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
	<application android:label="DemoApp.Android" android:theme="@style/MainTheme"></application>
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</manifest>

写入外部存储之前的第一步是检查它是可读或可写。 Android.OS.Environment.ExternalStorageState 属性保存标识外部存储状态的字符串。 此属性会返回表示状态的字符串。

代码语言:javascript复制
bool isReadonly = Environment.MediaMountedReadOnly.Equals(Environment.ExternalStorageState);
bool isWriteable = Environment.MediaMounted.Equals(Environment.ExternalStorageState);

完全限定

代码语言:javascript复制
bool isReadonly = Android.OS.Environment.MediaMountedReadOnly.Equals(Android.OS.Environment.ExternalStorageState);
            bool isWriteable = Android.OS.Environment.MediaMounted.Equals(Android.OS.Environment.ExternalStorageState);

应用生命周期

参考:

  • Xamarin.Forms 应用生命周期 - Xamarin | Microsoft Docs

Application 基类提供下列功能:

  • 生命周期方法 OnStartOnSleepOnResume
  • 页导航事件 PageAppearingPageDisappearing
  • 模式导航事件 ModalPushingModalPushedModalPoppingModalPopped

生命周期方法 Application 类包含三个虚拟方法,可以替代以响应生命周期更改:

  • OnStart - 在启动应用程序时调用它。
  • OnSleep - 每当应用程序转入后台时调用它。
  • OnResume - 应用程序发送到后台后恢复时调用。

布局

参考:

  • 搞懂Xamarin.Forms布局,看这篇应该就够了吧 - 何旭 - 博客园
  • JoesWeek/Cnblogs: 博客园第三方Android客户端,Xamarin App,Material Design风格
  • jsuarezruiz/awesome-xamarin-forms: A curated list of awesome Xamarin.Forms libraries and resources
  • Xamarin.Forms UI Snippets

JarBinding Bugly

Xamarin.Forms Shell

参考:

  • 创建 Xamarin.Forms Shell 应用程序 - Xamarin | Microsoft Docs
  • Xamarin.Forms 第28局:Shell - 简书
  • Xamarin.FormsShell基础教程(9)Shell相关类体系 - 大学霸 - 博客园

视觉层次结构

Shell -> FlyoutItem / TabBar -> Tab -> ShellContent -> ContentPage FloutItem: 浮出控件 TabBar: 底部选项卡栏 Tab: 分组内容 当 Tab 中存在多个 ShellContent,时,会在内部再次分布, 若 Tab 父级是 TabBar,则会在那个页面显示 顶部导航选项卡,以对应多个 ShellContent, 若 Tab 父级是 FlyoutItem,则会在对应条下显示多个子条 (ShellContent) 若在 FloutItem / TabBar 中直接写 ShellContent,则会将每个ShellContent 隐式包裹在一个 Tab

补充: 和 TabBar 类是 ShellItem 类的别名,而 Tab 类是 ShellSection 类的别名。 因此,也可以 Shell -> FlyoutItem / ShellItem -> ShellSection -> ShellContent -> ContentPage 因此,在为 FlyoutItem 对象创建自定义呈现器时应重写 CreateShellItemRenderer 方法,在为 Tab 对象创建自定义呈现器时应重写 CreateShellSectionRenderer 方法。

代码语言:javascript复制
<!-- When the Flyout is visible this will be a menu item you can tie a click behavior to  -->
<MenuItem Text="Logout" StyleClass="MenuItemLayoutStyle" Clicked="OnMenuItemClicked">
</MenuItem>

侧边浮出注销按钮

当 侧边 (Flyout) 浮出显示 时,MenItem 就会显示

MenuItem: 浮出控件的菜单项

浮出控件

参考:

  • Xamarin.Forms Shell 浮出控件 - Xamarin | Microsoft Docs

可以通过图标或从屏幕的一侧轻扫来访问它。 浮出控件由可选标头、浮出控件项、可选菜单项和可选页脚组成:

代码语言:javascript复制
<!-- 
	When the Flyout is visible this defines the content to display in the flyout.
	FlyoutDisplayOptions="AsMultipleItems" will create a separate flyout item for each child element    
	https://docs.microsoft.com/dotnet/api/xamarin.forms.shellgroupitem.flyoutdisplayoptions?view=xamarin-forms
-->
<FlyoutItem Title="首页" Icon="icon_about.png">
    <ShellContent Route="HomePage" ContentTemplate="{DataTemplate local:HomePage}" />
</FlyoutItem>
<FlyoutItem Title="列表" Icon="icon_feed.png">
    <ShellContent Route="ItemsPage" ContentTemplate="{DataTemplate local:ItemsPage}" />
</FlyoutItem>
<FlyoutItem Title="设置" Icon="icon_setting.png">
    <ShellContent Route="SettingPage" ContentTemplate="{DataTemplate local:SettingPage}" />
</FlyoutItem>

隐式转换

代码语言:javascript复制
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:controls="clr-namespace:Xaminals.Controls"
       xmlns:views="clr-namespace:Xaminals.Views"
       x:Class="Xaminals.AppShell">
    <FlyoutItem Title="Cats"
                Icon="cat.png">
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:CatsPage}" />
       </Tab>
    </FlyoutItem>
    <FlyoutItem Title="Dogs"
                Icon="dog.png">
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:DogsPage}" />
       </Tab>
    </FlyoutItem>
</Shell>

等同于下方:

代码语言:javascript复制
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:controls="clr-namespace:Xaminals.Controls"
       xmlns:views="clr-namespace:Xaminals.Views"
       x:Class="Xaminals.AppShell">
   <ShellContent Title="Cats"
                 Icon="cat.png"
                 ContentTemplate="{DataTemplate views:CatsPage}" />
   <ShellContent Title="Dogs"
                 Icon="dog.png"
                 ContentTemplate="{DataTemplate views:DogsPage}" />
</Shell>

此隐式转换自动将每个 ShellContent 对象包装在 Tab 对象中,而 Tab 则包装在 FlyoutItem 对象中。

Shell 中默认 FlyoutItem, FlyoutItem / TabBar 中默认 Tab

备注 子类化的 Shell 对象中的所有 FlyoutItem 对象都会自动添加到 Shell.FlyoutItems 集合, 该集合定义将在浮出控件中显示的项的列表。

定义 FlyoutItem 外观

通过将 Shell.ItemTemplate 附加属性设置为 DataTemplate 可自定义每个 FlyoutItem 的外观:

代码语言:javascript复制
<Shell ...>
    ...
    <Shell.ItemTemplate>
        <DataTemplate>
            <Grid ColumnDefinitions="0.2*,0.8*">
                <Image Source="{Binding FlyoutIcon}"
                       Margin="5"
                       HeightRequest="45" />
                <Label Grid.Column="1"
                       Text="{Binding Title}"
                       FontAttributes="Italic"
                       VerticalTextAlignment="Center" />
            </Grid>
        </DataTemplate>
    </Shell.ItemTemplate>
</Shell>

FontAttributes="Italic" 此示例以斜体显示每个 FlyoutItem 对象的标题:

Shell.ItemTemplate 是一个附加属性,因此可将不同的模板附加到特定的 FlyoutItem 对象。

替换浮出控件内容

浮出项表示浮出控件内容,可以选择将其替换为你自己的内容,方法是将 Shell.FlyoutContent 可绑定属性设置为 object

代码语言:javascript复制
<Shell ...
       x:Name="shell">
    ...
    <Shell.FlyoutContent>
        <CollectionView BindingContext="{x:Reference shell}"
                        IsGrouped="True"
                        ItemsSource="{Binding FlyoutItems}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Label Text="{Binding Title}"
                           TextColor="White"
                           FontSize="Large" />
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </Shell.FlyoutContent>
</Shell>

在此示例中,将浮出控件内容替换为 CollectionView,它显示了 FlyoutItems 集合中每个项的标题。

此外,可以通过将 Shell.FlyoutContentTemplate 可绑定属性设置为 DataTemplate 来定义浮出控件内容:

代码语言:javascript复制
<Shell ...
       x:Name="shell">
    ...
    <Shell.FlyoutContentTemplate>
        <DataTemplate>
            <CollectionView BindingContext="{x:Reference shell}"
                            IsGrouped="True"
                            ItemsSource="{Binding FlyoutItems}">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Label Text="{Binding Title}"
                               TextColor="White"
                               FontSize="Large" />
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </DataTemplate>
    </Shell.FlyoutContentTemplate>
</Shell>

FlyoutItem 选择

场景: 有时候,默认并不需要显示第一个

首次运行使用浮出控件的 Shell 应用程序时,Shell.CurrentItem 属性将设置为子类化的 Shell 对象中的第一个 FlyoutItem 对象。 但是,此属性可以设置为另一个 FlyoutItem,如以下示例所示:

代码语言:javascript复制
<Shell ...
       CurrentItem="{x:Reference aboutItem}">
    <FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
        ...
    </FlyoutItem>
    <ShellContent x:Name="aboutItem"
                  Title="About"
                  Icon="info.png"
                  ContentTemplate="{DataTemplate views:AboutPage}" />
</Shell>

此示例将 CurrentItem 属性设置为名为 aboutItemShellContent 对象,这将导致选中并显示该对象。 在此示例中,隐式转换用于将 ShellContent 对象包装在 Tab 对象中,后者包装在 FlyoutItem 对象中。

假设有一个名为 aboutItemShellContent 对象,则等效的 C# 代码为:

代码语言:javascript复制
CurrentItem = aboutItem;

在此示例中,CurrentItem 属性是在子类化的 Shell 类中设置的。 或者,可通过 Shell.Current 静态属性在任何类中设置 CurrentItem 属性:

代码语言:javascript复制
Shell.Current.CurrentItem = aboutItem;

FlyoutItem 可见性

浮出项在浮出控件中默认可见。 但是,可以使用 FlyoutItemIsVisible 属性将项隐藏在浮出控件中,并使用 IsVisible 属性将其从浮出控件中删除:

  • 类型为 boolFlyoutItemIsVisible 指示项是否已隐藏在浮出控件中但仍可以通过 GoToAsync 导航方法进行访问。 此属性的默认值为 true
  • 类型为 boolIsVisible 指示是否应从可视化树中移除项,从而不在浮出控件中显示。 它的默认值为 true

备注 还有一个 Shell.FlyoutItemIsVisible 附加属性,可在 FlyoutItemMenuItemTabShellContent 对象上设置该属性。

以编程方式打开和关闭浮出控件

代码语言:javascript复制
<Shell ...
       FlyoutIsPresented="{Binding IsFlyoutOpen}">
</Shell>
代码语言:javascript复制
Shell.Current.FlyoutIsPresented = false;

底部导航栏

参考:

  • Xamarin.Forms Shell 选项卡 - Xamarin | Microsoft Docs
代码语言:javascript复制
<TabBar>
    <ShellContent Title="About" Icon="icon_about.png" Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
    <ShellContent Title="Browse" Icon="icon_feed.png" ContentTemplate="{DataTemplate local:ItemsPage}" />
</TabBar>

目测,不加 Title, Icon 就会隐藏起来,那么这个时候就只能通过代码导航到这里了。

代码语言:javascript复制
<!--
	If you would like to navigate to this content you can do so by calling
	await Shell.Current.GoToAsync("//LoginPage");
-->
<TabBar>
    <ShellContent Route="LoginPage" ContentTemplate="{DataTemplate local:LoginPage}" />
</TabBar>

单页

TabBar 中只有 一个 ShellContent,就不会显示底部选项卡导航栏

代码语言:javascript复制
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:views="clr-namespace:Xaminals.Views"
       x:Class="Xaminals.AppShell">
    <TabBar>
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:CatsPage}" />
       </Tab>
    </TabBar>
</Shell>

底部选项卡

倘若单个 TabBar 对象中有多个 Tab 对象,则 Tab 对象呈现为底部选项卡:

类型为 stringTitle 属性,可定义选项卡标题。 类型为 ImageSourceIcon 属性,可定义选项卡图标:

如果 TabBar 上有五个以上的选项卡,则显示“更多”选项卡,可用于访问其他选项卡:

底部和顶部选项卡

如果一个 Tab 对象中存在多个 ShellContent 对象时,则将在底部选项卡中添加一个顶部选项卡栏,通过该选项卡栏可以导航 ContentPage 对象:

代码语言:javascript复制
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:views="clr-namespace:Xaminals.Views"
       x:Class="Xaminals.AppShell">
    <TabBar>
       <Tab Title="Domestic"
            Icon="paw.png">
           <ShellContent Title="Cats"
                         ContentTemplate="{DataTemplate views:CatsPage}" />
           <ShellContent Title="Dogs"
                         ContentTemplate="{DataTemplate views:DogsPage}" />
       </Tab>
       <Tab Title="Monkeys"
            Icon="monkey.png">
           <ShellContent ContentTemplate="{DataTemplate views:MonkeysPage}" />
       </Tab>
    </TabBar>
</Shell>

选项卡选择

首次运行使用选项卡栏的 Shell 应用程序时,Shell.CurrentItem 属性将设置为子类化的 Shell 对象中的第一个 Tab 对象。 但是,此属性可以设置为另一个 Tab,如以下示例所示:

代码语言:javascript复制
<Shell ...
       CurrentItem="{x:Reference dogsItem}">
    <TabBar>
        <ShellContent Title="Cats"
                      Icon="cat.png"
                      ContentTemplate="{DataTemplate views:CatsPage}" />
        <ShellContent x:Name="dogsItem"
                      Title="Dogs"
                      Icon="dog.png"
                      ContentTemplate="{DataTemplate views:DogsPage}" />
    </TabBar>
</Shell>

补充

同时显示 浮出、底部导航栏

参考:

  • Xamarin Form Shell:弹出型v/s TabBar - 我爱学
  • app shell - 在 Xamarin.Forms 中同时使用 TabBar 和 Flyout - 爱编程的大狗

没办法直接在Shell中,同时显式定义 FlyoutItemTabBar 只能通过 FlyoutItem 隐式达到效果

注意: 并没有在 FlyoutItem 上使用 FlyoutDisplayOptions="AsMultipleItems", 这会导致 首页、游戏、频道、动态也显示在侧边浮出栏

代码语言:javascript复制
<!-- 显示在底部导航栏 -->
<FlyoutItem Title="首页" Icon="icon_about.png">
    <Tab Title="首页" Icon="icon_about.png">
        <ShellContent x:Name="HotPageItem" 
                      Title="热门"
                      ContentTemplate="{DataTemplate local:HotPage}" />
        <ShellContent x:Name="RecomPageItem" 
                      Title="推荐"
                      ContentTemplate="{DataTemplate local:RecomPage}" />
        <ShellContent x:Name="LastPageItem" 
                      Title="最新"
                      ContentTemplate="{DataTemplate local:LastPage}" />
    </Tab>
    <Tab Title="游戏" Icon="icon_feed.png">
        <ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
    </Tab>
    <Tab Title="频道" Icon="icon_feed.png">
        <ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
    </Tab>
    <Tab Title="动态" Icon="icon_feed.png">
        <ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
    </Tab>
</FlyoutItem>
<!-- 显示在侧边浮出栏 -->
<FlyoutItem Title="关于" Icon="icon_about.png">
    <ShellContent ContentTemplate="{DataTemplate local:HomePage}" />
</FlyoutItem>
<FlyoutItem Title="设置" Icon="icon_setting.png">
    <ShellContent ContentTemplate="{DataTemplate local:SettingPage}" />
</FlyoutItem>

补充

让首页默认选中 第二个 推荐,在 首页 项使用 CurrentItem

代码语言:javascript复制
<Tab Title="首页" Icon="icon_about.png" CurrentItem="{x:Reference RecomPageItem}">
    <ShellContent x:Name="HotPageItem" 
                  Title="热门"
                  ContentTemplate="{DataTemplate local:HotPage}" />
    <ShellContent x:Name="RecomPageItem" 
                  Title="推荐"
                  ContentTemplate="{DataTemplate local:RecomPage}" />
    <ShellContent x:Name="LastPageItem" 
                  Title="最新"
                  ContentTemplate="{DataTemplate local:LastPage}" />
</Tab>

Shell 添加手势、滑动

参考:

  • c# - 在 Xamarin Shell 中的 tabbar 页面之间滑动_c _帮酷编程问答
  • [Feature] Swipe left/right to navigate between upper/bottom tabs of Shell · Issue #12435 · xamarin/Xamarin.Forms

官方没有实现 底部选项导航栏(包括子项顶部导航栏) 滑动动画切换页面 见 [Feature] Swipe left/right to navigate between upper/bottom tabs of Shell · Issue #12435 · xamarin/Xamarin.Forms

Xamarin.Forms 滑动、手势

参考:

  • softlion/XamarinFormsGesture: Xamarin Form Gesture Effects
  • Xamarin.Forms ScrollView - Xamarin | Microsoft Docs
  • Xamarin.Forms CarouselView 滚动 - Xamarin | Microsoft Docs

滚动视图 ScrollView 在Xamarin.Forms中,滚动视图ScrollView用来实现长内容的滚动显示。虽然ScrollView的Content属性只能设置一个值,即ScrollView只能包含一个子元素,但它实际是一个布局控件,一个特殊的布局元素。 在使用的时候,ScrollView要求父容器给它分配固定的大小,同时子元素并且有固定的大小。这样,ScrollView才能根据各自大小计算滚动量。ScrollView不仅提供了当前滚动量ScrollX和ScrollY,还提供内容总量ContentSize。这样,开发者就可以计算滚动进度,显示给用户。同时,利用ScrollView提供的滚动结束事件Scrolled,可以提示用户,或者加载新的内容。

Q&A

补充

解析 Markdown

参考:

  • NumerousTechnology/MdView: The flexible Markdown control for Xamarin.Forms.
  • dotnet-ad/MarkdownView: Native markdown rendering on top of Xamarin.Forms & Markdig.
  • SuavePirate/MarkdownTextView: A Xamarin.Forms component to display markdown text in a TextView

V**

参考:

  • c# - V**client in xamarin - Stack Overflow
  • vpnhood/VpnHood: Undetectable Fast Portable V**

内网穿透

参考:

  • FastTunnel/FastTunnel: 开源免费跨平台的内网穿透工具 远程内网计算机 域名访问内网站点 反向代理内网服务 花生壳 端口转发 http代理 微信 小程序 like ngrok and frp. NAT ssh proxy tunnel reverse-proxy

自动升级

参考:

  • C# Xamarin For Android自动升级项目实战 - 跟着阿笨一起玩.NET - 博客园
  • xamarin.forms 版本自动更新(针对android) - sxsean - 博客园
  • XamarinAndroid获取当前版本号-Android-CSDN问答
  • C#使用Xamarin开发可移植移动应用终章(11.获取设备信息与常用组件,开源一个可开发模版.) - GuZhenYin - 博客园
  • Android开发之自带下载器DownloadManager的使用示例代码_Android_脚本之家
  • android 8.0以上无法唤起apk安装界面问题_vulgar_rabbit的博客-CSDN博客
  • Android7.0、8.0安装apk以及安装apk弹出“选择打开方式”的解决方案_Lone_Star斌 的博客-CSDN博客
  • 系统自带DownloadManager详解_Demi的博客-CSDN博客
  • WVector/AppUpdate:

    0 人点赞