#svg #xamarin.forms #tabs
#svg #xamarin.forms #вкладки
Вопрос:
Я создаю простое приложение, в котором есть 3 вкладки, на каждой вкладке есть значок и текст. Пример проекта, на котором я основываю свой код, существует здесь:
Единственная проблема, которую я обнаружил с ним, это использование пикселизированных изображений для заголовков вкладок, которые я хотел бы изменить на файлы ресурсов SVG.
Я добавил библиотеку загрузки FFImageLoading и добавил поддержку svg отсюда
Мне удалось добавить изображение на одну из страниц содержимого вкладки, но я не вижу svg-изображения, которое я пытаюсь увидеть в заголовке.
Пока это мой код:
TodayPage.xaml.cs
public partial class TodayPage : ContentPage
{
public TodayPage()
{
InitializeComponent();
InitializeComponent();
// IconImageSource = "today.png"; <-- this will show the pixilated image
IconImageSource = SvgImageSource.FromResource("today.svg"); //<--not working
Title = "Today";
}
}
TodayPage.xaml
<?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:forms="clr-namespace:FFImageLoading.Svg.Forms;assembly=FFImageLoading.Svg.Forms"
x:Class="TabsApp.TodayPage">
<ContentPage.Content>
<StackLayout>
<forms:SvgCachedImage WidthRequest="200" HeightRequest="200" Source="resource://TabsApp.Resources.today.svg"/>
<Label Text="Today's appointments go here going" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
MainPage.xaml
<?xml version="1.0" encoding="UTF-8"?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabsApp;assembly=TabsApp"
x:Class="TabsApp.MainPage">
<local:TodayPage />
<NavigationPage Title="Schedule" IconImageSource="schedule.png">
<x:Arguments>
<local:SchedulePage />
</x:Arguments>
</NavigationPage>
<local:SettingPage />
</TabbedPage>
Спасибо
Редактировать
Благодаря Leon мне удалось загрузить svg-файл в Android. Я все еще пытаюсь загрузить файл svg в iOS.
Мне удалось создать пользовательский инструмент визуализации вкладок в iOS, вот код:
[assembly: ExportRenderer(typeof(TabPage), typeof(PageTabRenderer))]
namespace TabsApp.iOS
{
[Foundation.Preserve(AllMembers = true)]
public class PageTabRenderer : TabbedRenderer
{
protected override async Task<Tuple<UIImage, UIImage>> GetIcon(Page page)
{
var navigationPage = page as NavigationPage;
if (navigationPage != null amp;amp; navigationPage.CurrentPage != null)
{
var imageSource = navigationPage.IconImageSource == null ? navigationPage.CurrentPage.IconImageSource : navigationPage.IconImageSource;
return await this.GetNativeUIImage(imageSource);
}
return await this.GetNativeUIImage(page.IconImageSource);
}
private async Task<Tuple<UIImage, UIImage>> GetNativeUIImage(ImageSource imageSource)
{
var imageicon = await GetNativeImageAsync(imageSource);
return new Tuple<UIImage, UIImage>(imageicon, null);
}
private async Task<UIImage> GetNativeImageAsync(ImageSource imageSource)
{
if (imageSource is FileImageSource fileImage amp;amp; fileImage.File.Contains(".svg"))
{
var imageicon = await ImageService.Instance.LoadFile(fileImage.File).WithCustomDataResolver(new SvgDataResolver(15, 15, true)).AsUIImageAsync();
return imageicon.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
}
else
{
var imageicon = await GetUIImage(imageSource);
return imageicon.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
}
}
private Task<UIImage> GetUIImage(ImageSource imageSource)
{
var handler = GetImageSourceHandler(imageSource);
return handler.LoadImageAsync(imageSource);
}
private static IImageSourceHandler GetImageSourceHandler(ImageSource source)
{
IImageSourceHandler sourceHandler = null;
if (source is UriImageSource)
sourceHandler = new ImageLoaderSourceHandler();
else if (source is FileImageSource)
sourceHandler = new FileImageSourceHandler();
else if (source is StreamImageSource)
sourceHandler = new StreamImagesourceHandler();
else if (source is FontImageSource)
sourceHandler = new FontImageSourceHandler();
return sourceHandler;
}
}
}
this is my mainpage.xaml
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabsApp;assembly=TabsApp"
x:Class="TabsApp.MainPage">
<local:TodayPage />
<NavigationPage Title="Schedule" IconImageSource="today1.svg">
<x:Arguments>
<local:SchedulePage />
</x:Arguments>
</NavigationPage>
<local:SettingPage />
</TabbedPage>
I also copied TabPage class but I don’t see the svg icons loading. I tried to debug it and it seems the GetIcon is never called.
****** Edit 2 *******
After more playing with the code here and there I managed to figure it out. If someone will be interested in implementing similar design
main.xaml
<?xml version="1.0" encoding="UTF-8"?>
<custom:TabPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabsApp;assembly=TabsApp"
xmlns:custom="clr-namespace:TabsApp.custom;assembly=TabsApp"
x:Class="TabsApp.MainPage"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
android:TabbedPage.IsSmoothScrollEnabled="True"
android:TabbedPage.IsSwipePagingEnabled="False"
xmlns:iOS="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
xmlns:ffimageloadingsvg="clr-namespace:FFImageLoading.Svg.Forms;assembly=FFImageLoading.Svg.Forms"
iOS:Page.UseSafeArea="true" NavigationPage.HasNavigationBar="False"
BarTextColor="{DynamicResource SecondaryTextColor}" UnselectedTabColor="Black" SelectedTabColor="Blue"
NavigationPage.HasBackButton="False">
<local:TodayPage IconImageSource="{x:OnPlatform Android=ic_today, iOS=today-24px.svg}"/>
<local:SchedulePage IconImageSource="{x:OnPlatform Android=ic_schedule, iOS=schedule-24px.svg}"/>
<local:SettingPage IconImageSource="{x:OnPlatform Android=ic_settings, iOS=settings-24px.svg}"/>
</custom:TabPage>
Важно отметить две вещи: IconImageSource будет изменен в зависимости от платформы, SelectedTabColor будет цветом оттенка как для Android, так и для iOS, когда выбран элемент вкладки.
вам нужно преобразовать файлы svg в векторные файлы, которые можно рисовать, как писал Lean, и поместить их в папку / drawable .
Что касается iOS, вам нужно будет добавить пользовательский инструмент визуализации вкладок, который я использовал:
[assembly: ExportRenderer(typeof(TabPage), typeof(PageTabRenderer))]
namespace TabsApp.iOS
{
[Foundation.Preserve(AllMembers = true)]
public class PageTabRenderer : TabbedRenderer
{
readonly nfloat imageYOffset = 7.0f;
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (TabBar.Items != null)
{
foreach (var item in TabBar.Items)
{
item.Title = null;
item.ImageInsets = new UIEdgeInsets(imageYOffset, 0, -imageYOffset, 0);
}
}
}
protected override async Task<Tuple<UIImage, UIImage>> GetIcon(Page page)
{
var navigationPage = page as NavigationPage;
if (navigationPage != null amp;amp; navigationPage.CurrentPage != null)
{
var imageSource = navigationPage.IconImageSource == null ? navigationPage.CurrentPage.IconImageSource : navigationPage.IconImageSource;
return await this.GetNativeUIImage(imageSource);
}
return await this.GetNativeUIImage(page.IconImageSource);
}
private async Task<Tuple<UIImage, UIImage>> GetNativeUIImage(ImageSource imageSource)
{
var imageicon = await GetNativeImageAsync(imageSource);
return new Tuple<UIImage, UIImage>(imageicon, null);
}
private async Task<UIImage> GetNativeImageAsync(ImageSource imageSource)
{
if (imageSource is FileImageSource fileImage amp;amp; fileImage.File.Contains(".svg"))
{
var imageicon = await ImageService.Instance.LoadFile(fileImage.File).WithCustomDataResolver(new SvgDataResolver(15, 15, true)).AsUIImageAsync();
return imageicon.ImageWithRenderingMode(UIImageRenderingMode.Automatic);
}
else
{
var imageicon = await GetUIImage(imageSource);
return imageicon.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
}
}
private Task<UIImage> GetUIImage(ImageSource imageSource)
{
var handler = GetImageSourceHandler(imageSource);
return handler.LoadImageAsync(imageSource);
}
private static IImageSourceHandler GetImageSourceHandler(ImageSource source)
{
IImageSourceHandler sourceHandler = null;
if (source is UriImageSource)
sourceHandler = new ImageLoaderSourceHandler();
else if (source is FileImageSource)
sourceHandler = new FileImageSourceHandler();
else if (source is StreamImageSource)
sourceHandler = new StreamImagesourceHandler();
else if (source is FontImageSource)
sourceHandler = new FontImageSourceHandler();
return sourceHandler;
}
}
}
Поместите все файлы * .svg в папку /Resources в папке * .iOS и все.
Комментарии:
1. today.svg добавлен как встроенный ресурс правильно? (извините за очевидный вопрос, но просто проверяю)
Ответ №1:
Я получил тот же результат, вот мой обходной путь для svg-изображения на панели вкладок.
Для Android, пожалуйста, посетите эту страницу https://shapeshifter.design /
Затем импортируйте свой SVG-файл на веб-сайт, затем загрузите XML-файл, как показано ниже (нажмите Import
, выберите svg
, выберите svg-файл, затем выберите Export
, векторное изображение, загрузите XML-файл). Скопируйте XML-файл в папку Android Resource/ Drawable
(пожалуйста, проверьте, что действие сборки AndroidResource
относится к XML-файлу). Примечание: если вы хотите изменить цвет строки svg-файла, пожалуйста, откройте xml, выберите цвет заливки, измените его.
Затем вы можете использовать его в pcl XML, как следующий код.
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App3" xmlns:ffimageloadingsvg="clr-namespace:FFImageLoading.Svg.Forms;assembly=FFImageLoading.Svg.Forms"
BarBackgroundColor="Green"
x:Class="App3.MainPage">
<local:TodayPage IconImageSource="{x:OnPlatform Android=ic_today,iOS=today.svg}" >
</local:TodayPage>
<NavigationPage Title="Schedule" IconImageSource="myIcon.png">
<x:Arguments>
<local:Page1 />
</x:Arguments>
</NavigationPage>
</TabbedPage>
Вот скриншот запуска.
Для IOS, пожалуйста, обратитесь к Dinesh_Official
ответу в этой теме:
https://forums.xamarin.com/discussion/179773/how-to-use-svg-image-for-tabbed-page-tabbar-icon
Комментарии:
1. Решение для Android сработало для меня, я все еще не уверен, как реализовать вариант iOS, а также как различать android и iOS, когда дело доходит до загрузки разных ресурсов / рендеринга
2. Lean Lu, нужно ли мне создавать средство визуализации вкладок для каждой вкладки, которая у меня будет?
3. @DemoDemo В IOS вам следует создать пользовательский рендеринг для вашей страницы с вкладками, затем переопределить
GetIcon
метод, вот демонстрация code.github.com/dinesh4official/XFPage/blob/master/XFPage/XFPage.iOS /. … Вы также можете загрузить его.4. Я обновил свой вопрос, похоже, GetIcon никогда не вызывается. Я прикрепил свой новый код в исходном сообщении. Я ценю вашу помощь!
Ответ №2:
Для отладки SVG-файлов вот несколько шагов, которые могут помочь.
-
Будет ли работать другой подтвержденный рабочий SVG, если вы его заменили? Если нет, инициализирована ли загрузка ffimageloading?
-
Подтвердите свои встроенные ресурсы. (поместите это в App.xaml.cs)
public static void PrintEmbeddedResources()
{
#if DEBUG
var assembly = typeof(App).GetTypeInfo().Assembly;
var logTxt = "Embedded Resources:" Environment.NewLine;
foreach (var res in assembly.GetManifestResourceNames())
{
Debug.WriteLine("found resource: " res);
}
#endif
}
-
убедитесь, что ваш svg оптимизирован. Вот инструмент, который рекомендует ffimageloading: https://jakearchibald.github.io/svgomg /
-
загрузка ffimageloading иногда вызывает проблемы с определенными SVG. Проверьте проблемы на их github, чтобы узнать, сообщал ли кто-нибудь еще о проблеме, похожей на вашу, и, надеюсь, опубликовал обходной путь.
Комментарии:
1. 1. Я не уверен, оптимизированы ли они, я скачал один отсюда material.io/resources/icons/?style=baseline 2. Ресурс является встроенным ресурсом, я вижу его в debug, вводящем цикл с правильным именем. 3. Я использовал CachedImageRenderer. Init(true); var ignore = typeof(SvgCachedImage); как в вики ffimageloading