You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A simple program that binds an UITableView source to items with multiple texts and binds those texts to UILabels works incorrectly.
When the list is updated and overflowing cells are reused, the reused cells sometimes update their bindings only one frame after the cell is drawn on the screen. This causes visible flickering to the user.
Tested on MvvmCross 8.0.2 and iOS 15.2 emulator and real devices.
Expected behavior
Reused cells update their bindings before they are drawn. Appeared cells should not display old data.
Reproduction steps
Add the following ViewModel to the core and navigate to it.
FlickerTestViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MvvmCross.ViewModels;
namespace flickertest.Core.ViewModels
{
public class FlickeringItem
{
static string[] titles = { "one", "two", "three", "four", "five", "six", "seven", "eight", "potato", "milk", "carrot", "bread" };
static Random r = new Random();
public string Title { get; set; }
public string TimeText { get; set; }
public string XExercisesText { get; set; }
public static FlickeringItem GenerateRandom()
{
var item = new FlickeringItem();
item.Title = GetRandomTitle();
item.TimeText = GetRandomTitle();
item.XExercisesText = GetRandomTitle();
return item;
}
private static string GetRandomTitle()
{
List<string> words = new List<string>();
for (int i = 0; i < r.Next(3, 10); i++)
{
words.Add(titles[r.Next(0, titles.Count())]);
}
return string.Join(" ", words);
}
}
public class FlickerTestViewModel : MvxViewModel
{
Random r = new Random();
private List<FlickeringItem> listItems;
public List<FlickeringItem> ListItems
{
get { return listItems; }
set
{
if (value == listItems) return;
listItems = value;
RaisePropertyChanged(() => ListItems);
}
}
public FlickerTestViewModel()
{
}
public override async Task Initialize()
{
await base.Initialize();
_ = SampleLoop();
}
private async Task SampleLoop()
{
for (int i = 0; i < 20; i++)
{
await Task.Delay(3000).ConfigureAwait(true);
ListItems = GenerateData();
}
}
private List<FlickeringItem> GenerateData()
{
var res = new List<FlickeringItem>();
for (int i = 0; i < r.Next(10, 35); i++)
{
res.Add(FlickeringItem.GenerateRandom());
}
return res;
}
}
}
Here is the code for the view and it's cells.
FlickerTestView:
using MvvmCross.Platforms.Ios.Binding.Views;
using MvvmCross.Platforms.Ios.Views;
using MvvmCross.Binding.BindingContext;
using Foundation;
using UIKit;
using flickertest.Core.ViewModels;
namespace flickertest.iOS.Views
{
public class FlickerTestView : MvxTableViewController<FlickerTestViewModel>
{
public FlickerTestView()
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var Source = new MvxSimpleTableViewSource(TableView, ItemCell.Identifier);
TableView.RegisterClassForCellReuse(typeof(ItemCell), ItemCell.Identifier);
TableView.Source = Source;
TableView.RowHeight = 80;
var set = this.CreateBindingSet<FlickerTestView, FlickerTestViewModel>();
set.Bind(Source).For(s => s.ItemsSource).To(s => s.ListItems).OneWay();
set.Apply();
}
}
public class ItemCell : MvxTableViewCell
{
public static NSString Identifier = new NSString(nameof(ItemCell));
private UILabel _title, _title2, _title3;
public ItemCell(IntPtr handle) : base(handle)
{
Initialize();
}
public ItemCell()
{
Initialize();
}
private void Initialize()
{
_title = new UILabel { TranslatesAutoresizingMaskIntoConstraints = false };
_title2 = new UILabel { TranslatesAutoresizingMaskIntoConstraints = false };
_title3 = new UILabel { TranslatesAutoresizingMaskIntoConstraints = false };
ContentView.Add(_title);
ContentView.Add(_title2);
ContentView.Add(_title3);
_title.LeadingAnchor.ConstraintEqualTo(ContentView.LeadingAnchor, 10).Active = true;
_title.TrailingAnchor.ConstraintEqualTo(ContentView.TrailingAnchor, -10).Active = true;
_title.CenterYAnchor.ConstraintEqualTo(ContentView.CenterYAnchor).Active = true;
_title2.LeadingAnchor.ConstraintEqualTo(ContentView.LeadingAnchor, 10).Active = true;
_title2.TrailingAnchor.ConstraintEqualTo(ContentView.TrailingAnchor, -10).Active = true;
_title2.BottomAnchor.ConstraintEqualTo(_title.TopAnchor,-5).Active = true;
_title3.LeadingAnchor.ConstraintEqualTo(ContentView.LeadingAnchor, 10).Active = true;
_title3.TrailingAnchor.ConstraintEqualTo(ContentView.TrailingAnchor, -10).Active = true;
_title3.TopAnchor.ConstraintEqualTo(_title.BottomAnchor,5).Active = true;
var set = this.CreateBindingSet<ItemCell, FlickeringItem>();
set.Bind(_title).To(vm => vm.Title);
set.Bind(_title2).To(vm => vm.TimeText);
set.Bind(_title3).To(vm => vm.XExercisesText);
set.Apply();
}
}
}
Configuration
Version: 8.0.2
Platform:
[ x] 馃摫 iOS
馃 Android
馃弫 WPF
馃寧 UWP
馃崕 MacOS
馃摵 tvOS
馃悞 Xamarin.Forms
The text was updated successfully, but these errors were encountered:
I did some further simplification and the problem is even more obvious when the list items are not changed but instead a new list containing the same items is created:
ListItems = new List<FlickeringItem>(ListItems);
The order of the items stays the same, but some of the text labels flicker for a single frame.
This problem is urgent for us and we are looking to find some help on this.
Thank you, I solved this by keeping the rest of the bindings and setting the problematic values manually in protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
馃悰 Bug Report
A simple program that binds an UITableView source to items with multiple texts and binds those texts to UILabels works incorrectly.
When the list is updated and overflowing cells are reused, the reused cells sometimes update their bindings only one frame after the cell is drawn on the screen. This causes visible flickering to the user.
Tested on MvvmCross 8.0.2 and iOS 15.2 emulator and real devices.
Expected behavior
Reused cells update their bindings before they are drawn. Appeared cells should not display old data.
Reproduction steps
Add the following ViewModel to the core and navigate to it.
FlickerTestViewModel:
Here is the code for the view and it's cells.
FlickerTestView:
Configuration
Version: 8.0.2
Platform:
The text was updated successfully, but these errors were encountered: