iOS: ListView header flickers when being updated
I have searched and made sure there are no existing issues for the issue I am filing
- [X] I have searched the existing issues
Description
Updating the header view of listview will cause it to flicker.
https://user-images.githubusercontent.com/1299558/212501809-11880a41-faa4-42b3-86be-ee636dc9f9c0.mov
Expected Behavior
The header view should not flicker
Actual behavior
The header view flickers
Reproducible sample
const win = Ti.UI.createWindow();
const headerView = Ti.UI.createView({ height: 200, backgroundColor: 'red' });
const listView = Ti.UI.createListView({
headerView,
sections: [ Ti.UI.createListSection({ items: [ {properties: { title: 'Apple'}},{properties: { title: 'Banana'}} ] }) ]
});
setInterval(() => {
headerView.height++;
}, 1000);
win.add(listView);
win.open();
Steps to reproduce
Install the code on a device (does not happen in simulator) and run it. The issue should be apparent. We've seen this on iPhone 13, but not on earlier versions.
Platform
No response
SDK version you are using
12.0.0.GA.
Alloy version you are using
2.0.1
@prashantsaini1 Can you please reproduce this? Trying to get this fixed next week.
@hansemannn @jonasfunk
Findings:
- This bug is reproducible on simulator as well. Reducing the
setIntervalduration to 500ms or lower causes faster flickering.
Issue Cause:
- When the
headerViewis part of theListView, there are lots of UI updates happen internally on the entire view hierarchy, even reloading the entire data insideframeSizeChangedinTiUIListView.mclass. - I tried at 2s interval and the flickering didn't occur. Only noticed it on 1s or lower when updating the UI repeatedly.
- So the flickering only happens when we do UI updates too often.
Solution:
- I am not sure what would be the case to do such frequent UI updates. But here's an existing solution already:
- The
replaceSectionAtdoes not trigger any view updates or data reloads. - Moving
headerViewinside the firstListSectionand then updating it usingreplaceSectionAtmakes the flickering gone.
Code without flickering:
const win = Ti.UI.createWindow();
const headerView = Ti.UI.createView({ height: 200, backgroundColor: 'red', top: 0 });
const listView = Ti.UI.createListView({
style: Ti.UI.iOS.ListViewStyle.GROUPED, // make the headerView non-sticky while scrolling
sections: [
Ti.UI.createListSection({
headerView,
items: [ {properties: { title: 'Apple'}},{properties: { title: 'Banana'}} ]
})
],
});
setInterval(() => {
headerView.height += 2;
// this is important to reflect the updated height of the headerView
listView.replaceSectionAt(0, listView.sections[0]);
}, 100);
win.add(listView);
win.open();
| headerView inside ListView - 100ms | headerView inside ListSection - 50ms |
|---|---|
That makes a lot of sense, thank you! @jonasfunk Can you try one of the two suggestions? We usually use the section based header view solution very successfully.
Thanks for the feedback. I’ve tried to follow the suggestion of using the section header instead. It’s a bigger task since we have quite a few controllers that make up the individual header views. Some of these controllers may trigger frame change events.
The good thing about this approach is that you get animation of height changes.
However, I’m occasionally experiencing that the header height updates correctly, but the content doesn’t follow along — so it gets clipped at its previous height. The image below shows an example of this. The red border defines the headerview, that has gotten the correct height, while the content, defined by the blue border, remains at its height. The layout in the header is vertical - I'm guessing it has something to do with that.
@jonasfunk Can you share a video and some code snippet (exclude private code pieces) of what you're actually trying to achieve?