[英]Scrollview control not working properly in .Net MAUI (Android)
I have created custom tab control using ScrollView control and Bindable StackLayout control.我使用 ScrollView 控件和 Bindable StackLayout 控件创建了自定义选项卡控件。
I have first created this solution in Xamarin.Forms (VS for Mac 2019) and it works fine in both platforms, but the same solution when developed in .Net MAUI (VS for Mac 2022 Prev) it's not working properly in Android.我首先在 Xamarin.Forms(VS for Mac 2019)中创建了这个解决方案,它在两个平台上都可以正常工作,但是在 .Net MAUI(VS for Mac 2022 Prev)中开发的相同解决方案在 Android 中无法正常工作。
There is an issue with BindableLayout (StackLayout) properties in MAUI currently so when we are changing values it does not get reflected, and because of this, I think I'm facing this issue.目前 MAUI 中的 BindableLayout (StackLayout) 属性存在问题,因此当我们更改值时,它不会得到反映,因此,我认为我正面临这个问题。 Here is the reference
这是参考
Here is what I have done so far:这是我到目前为止所做的:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:poc_maui.ViewModels"
x:Class="poc_maui.Views.HomePage"
xmlns:tabs="clr-namespace:poc_maui.Views.SubViews"
Title="HomePage">
<ContentPage.BindingContext>
<vm:MainPageViewModel />
</ContentPage.BindingContext>
<Grid RowDefinitions="50, *" RowSpacing="0">
<ScrollView Grid.Row="0" Orientation="Horizontal" VerticalOptions="Start" HorizontalScrollBarVisibility="Never"
Scrolled="ScrollView_Scrolled">
<StackLayout x:Name="TabsView"
Orientation="Horizontal"
BindableLayout.ItemsSource="{Binding Tabs}" Spacing="0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="*, 4" RowSpacing="0">
<Label Grid.Row="0"
Text="{Binding TabTitle}"
TextColor="White"
BackgroundColor="navy"
Padding="20,0"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
FontSize="12"
HeightRequest="40"/>
<BoxView Grid.Row="1"
Color="Yellow"
IsVisible="{Binding IsSelected}"/>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.TabChangedCommand,
Source={x:Reference TabsView}}"
CommandParameter="{Binding .}"/>
</Grid.GestureRecognizers>
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
<tabs:ParentRecordTabView Grid.Row="1" IsVisible="{Binding IsParentRecordTabVisible}"
VerticalOptions="FillAndExpand"/>
<tabs:AdditionalInfoTabView Grid.Row="1" IsVisible="{Binding IsAdditionalInfoTabVisible}"
VerticalOptions="FillAndExpand" />
</Grid>
</ContentPage>
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;
using poc_maui.Models;
namespace poc_maui.ViewModels
{
public class MainPageViewModel : BaseViewModel
{
#region Constructor
public MainPageViewModel()
{
GetTabs();
}
#endregion
#region Private Properties
private bool _isParentRecordTabVisible = true;
private bool _isAdditionalInfoTabVisible;
private ObservableCollection<TabViewModel> _tabs { get; set; }
#endregion
#region Public Properties
public bool IsParentRecordTabVisible
{
get => _isParentRecordTabVisible;
set { _isParentRecordTabVisible = value; OnPropertyChanged(nameof(IsParentRecordTabVisible)); }
}
public bool IsAdditionalInfoTabVisible
{
get => _isAdditionalInfoTabVisible;
set { _isAdditionalInfoTabVisible = value; OnPropertyChanged(nameof(IsAdditionalInfoTabVisible)); }
}
public ObservableCollection<TabViewModel> Tabs
{
get => _tabs;
set { _tabs = value; OnPropertyChanged(nameof(Tabs)); }
}
#endregion
#region Commands
public ICommand TabChangedCommand { get { return new Command<TabViewModel>(ChangeTabClick); } }
#endregion
#region Private Methods
private void GetTabs()
{
Tabs = new ObservableCollection<TabViewModel>();
Tabs.Add(new TabViewModel { TabId = 1, IsSelected = true, TabTitle = "Parent record" });
Tabs.Add(new TabViewModel { TabId = 2, TabTitle = "Additional Info" });
Tabs.Add(new TabViewModel { TabId = 3, TabTitle = "Contacts" });
Tabs.Add(new TabViewModel { TabId = 4, TabTitle = "Previous inspections" });
Tabs.Add(new TabViewModel { TabId = 5, TabTitle = "Attachments" });
SelectedTab = Tabs.FirstOrDefault();
}
private void ChangeTabClick(TabViewModel tab)
{
try
{
var tabs = new ObservableCollection<TabViewModel>(Tabs);
foreach (var item in tabs)
{
if (item.TabId == tab.TabId)
{
item.IsSelected = true;
}
else
{
item.IsSelected = false;
}
}
Tabs.Clear();
Tabs = new ObservableCollection<TabViewModel>(tabs);
switch (tab.TabId)
{
case 1:
IsParentRecordTabVisible = true;
IsAdditionalInfoTabVisible = false;
break;
case 2:
IsParentRecordTabVisible = false;
IsAdditionalInfoTabVisible = true;
break;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
#endregion
}
}
#ParentTabView.xaml #ParentTabView.xaml
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="poc_maui.Views.SubViews.ParentTabView">
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" >
<Label
Text="Welcome to Parent tab!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentView>
#AdditionalInfoTabView.xaml #AdditionalInfoTabView.xaml
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="poc_maui.Views.SubViews.AdditionalInfoTabView">
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" >
<Label
Text="Welcome to Additiona info tab!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentView>
So what happens here in Android is when I'm clicking AdditionalInfo Tab then it will show a blank white screen and if you press the hardware back button and open the app again it will show AdditionalTab as selected and its views content as well.因此,在 Android 中发生的情况是,当我单击 AdditionalInfo 选项卡时,它将显示一个空白的白色屏幕,如果您按下硬件后退按钮并再次打开应用程序,它将显示 AdditionalTab 已选中,并且它的视图内容也将显示。
If I remove switch() code part from the ViewModel then it will work fine but tabs will not change.如果我从 ViewModel 中删除 switch() 代码部分,那么它会正常工作,但选项卡不会改变。 Does anyone have idea about this kind of behavior of scroll view in MAUI?
有人知道 MAUI 中滚动视图的这种行为吗?
Does this work-around fix it?这个变通办法能解决吗?
MainPage.xaml: MainPage.xaml:
<ScrollView x:Name "theScrollView" ... >
MainPage.xaml.cs: MainPage.xaml.cs:
public MainPage()
{
InitializeComponent();
MessagingCenter.Subscribe<MainPageViewModel>(this, "update", (sender) =>
{
// Tell theScrollView to re-layout its contents.
(theScrollView as IView).InvalidateArrange();
});
}
MainPageViewModel:主页面视图模型:
private void ChangeTabClick(TabViewModel tab)
{
... make changes ...
MessagingCenter.Send<MainPageViewModel>(this, "update");
}
MAYBE:也许:
I'm not sure if MessagingCenter Subscribe is on Dispatcher (Main) thread.我不确定 MessagingCenter 订阅是否在调度程序(主)线程上。 To be reliable, do:
为了可靠,请执行以下操作:
MessagingCenter.Subscribe<MainPageViewModel>(this, "update", (sender) =>
{
Dispatcher.Dispatch( () =>
{
(theScrollView as IView).InvalidateArrange();
});
}
UPDATE更新
There are other Maui bugs, that have a common "theme": Maui on Android does "something" related to layout only once - at the time the page is first drawn.还有其他 Maui 错误,它们有一个共同的“主题”:Android 上的 Maui 只做了一次与布局相关的“事情”——在第一次绘制页面时。 UNFORTUNATELY, anything that is "not visible" at that time, is skipped.
不幸的是,当时“不可见”的任何内容都会被跳过。 And won't work when later made visible.
并且在以后变得可见时将不起作用。
Until such bugs are fixed, you'll have to do some work-around.在修复此类错误之前,您必须做一些工作。
WORK-AROUND #1:解决方法 #1:
IsVisible="True"
.IsVisible="True"
开始。InvalidateArrange
as shown above, to force the Bindings to function the first time.InvalidateArrange
,以强制 Bindings 第一次运行。 OR WORK-AROUND #2:或解决方法 #2:
Both of these are ugly.这两个都很丑。
I recommend creating an issue at .Net Maui github, and providing link to your github sample.我建议在 .Net Maui github 上创建一个问题,并提供指向您的 github 示例的链接。
This is still not works for me properly but after looking at below two links I found that it it not what we are looking for.这仍然不适用于我,但在查看下面的两个链接后,我发现它不是我们正在寻找的。 The Isvisible : false first and then on switch or check box change you are trying to make it visible then it will not visible but the actual control visible.
Isvisible : false 首先在开关或复选框更改上尝试使其可见,然后它将不可见,但实际控件可见。 So on look after I have see this link but again the answer is not what I was looking for.
所以在我看到这个链接之后,但答案又不是我想要的。
Step to resolve.一步解决。
<ScrollView x:Name "myScrollView"> ..... <ScrollView x:Name "myScrollView"> .....
... ...
public delegate void Action(T obj);公共委托无效动作(T obj);
MeasureAction?.Invoke("reSetVisibility"); MeasureAction?.Invoke("reSetVisibility");
Here Call the below line will works perfectly.这里调用下面的行将完美地工作。
(myScrollView as IView).InvalidateMeasure(); (myScrollView 作为 IView).InvalidateMeasure();
That's IT... Enjoy IsVisible now and make your layout as require.就是这样......现在享受 IsVisible 并根据需要进行布局。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.