[Android] Layout changes are not rendered without triggering a render cycle via interaction with UI
- Dominant language
- C#
- Stars
- 23.3k
- Forks
- 2k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 290
Description
### Description
I have a layout that I am optimizing for Portrait and Landscape modes respectively.
When I rotate the device, I change some layout values, such as the `HorizontalOptions` and `VerticalOptions` of certain Views that I would like to reposition in response to the size change for which I have an overide of `OnSizeAllocated()`. I am using the **VisualStateManager** to update the layout, but I've encountered exactly the same issue when I manually set the values in the code-behind or via bindings.
The problem is that there seems to be a render cycle missing after updating the layout. The changes only get applied when I add some UI interaction, such as a button press that triggers a _PropertyChanged_ event on some property. This problem applies to all kinds of Views, such as Grids, StackLayouts, Labels and Buttons.
In the following example to reproduce the issue, there is a button that is centered at the bottom in Portrait mode and moved to the right hand-side when going into Landscape mode. The button only changes its position after pressing it instead of updating immediately:
**XAML**
```xml
<Setter Property="Margin" Value="20" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Portrait">
<VisualState.Setters>
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="End" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Landscape">
<VisualState.Setters>
<Setter Property="HorizontalOptions" Value="End" />
<Setter Property="VerticalOptions" Value="Center" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
```
**Code-behind**
```c#
namespace MauiViewUpdateBug;
public partial class MainPage : ContentPage
{
public int Clicks { get; set; }
public MainPage()
{
InitializeComponent();
BindingContext = this;
}
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
VisualStateManager.GoToState(MyButton, width > height ? "Landscape" : "Portrait");
}
private void MyButton_OnClicked(object sender, EventArgs e)
{
Clicks++;
OnPropertyChanged(nameof(Clicks));
}
}
```
**Note: This only occurs on Android, on iOS it works fine. This happens with real devices, not tested with emulators. I can reproduce this on Samsung S22 and S10 devices (at least).**
### Steps to Reproduce
1. Create a new MAUI project
2. Add the XAML and Code-behind like in the sample
3. Run the App on an Android device
4. Rotate the Device
Expected Behavior: The Button moves to the right in Landscape mode
Actual Behavior: The Button stays where it is and only updates its position after pressing it
### Link to public reproduction project repository
https://github.com/ewerspej/dotnet-maui-bug-view-update
### Version with bug
7.0.0-rc.1.22426.10
### Last version that worked well
Unknown/Other
### Affected platforms
Android
### Affected platform versions
Android 12.0
### Did you find any workaround?
No
### Relevant log output
_No response_
Contributor guide
Research direction
Start by running the provided XAML and code-behind reproduction on a physical Android device and rotate it between portrait and landscape. Trace the VisualStateManager state change from OnSizeAllocated and compare it with the later update caused by the button click; done means the button repositions immediately after rotation without UI interaction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, csharp
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100