-
Notifications
You must be signed in to change notification settings - Fork 520
Description
Problem descriptione
ScrollablePositionedList has a bug with calculating Y position, and occasionally skips a row of pixels when stacking list items (or the pixel calculations in Flutter that it is using have bug).
Under some conditions every two rows the widget will leave a line of blank pixels between list items.
This lets the background color show through as a "line" between list items. This behavior prevents creating a stacked list of continuous colored widgets without unwanted "visual separator bars" appearing between list rows.
I have traced this down far enough to determine that it's a combined effect of:
- Pixel height of list items
- Scaling factor for Windows operating system
It only occurs in Windows (have tested on mac).
It only occurs when:
- list row heights are an ODD number of pixels (e.g. 23 vs 24)
- The scaling factor in Windows is set to some non-integer multiplier (e.g. 125%, 150%, 175%... vs 100%, 200%, 300%)
In drawing rows a situation occurs where:
- row N ends on pixel line Y
- row N+1 should therefore start drawing on line Y+1
- drawing actually starts on line Y+2
(Calculations of "start of row N+1" are coming out 1px more than they should every two rows, causing gaps.)
This is a very big deal if list is to be visually continuous scrollable content without row gaps.
[Note: scaling factors of 150%, etc, are extremely common for modern higher-density monitors. Windows actually labels 150% as "150% (recommended)" in the list for my 27" 4k monitor, for instance. It would be mistake to minimize this because you think "no one sets their monitor to 150%."]
Might be tolerable if it were doing it every row, could pretend it's part of my design for the UI or something. But having it happen every two rows just shows it's clearly a UI bug and my customers will yell at me for not fixing it.
Steps to reproduce
I only have one Windows machine to test on, but it's 100% reproducible on this machine.
- Ensure you can control height of List rows (I experienced it with complex-widget list rows, but eventually narrowed the behavior down using just Containers with fixed height).
- Run as a desktop app in Windows (ONLY; behavior is fine on MacOS, haven't tried on mobile)
- In windows settings, set Display control panel setting for scaling to some non-integer scale factor (i.e. 125%, 150%, not 100%, 200%, etc).
- Observe that with non-integer scale multiplier (e.g. 1.25, 1.5) Flutter is fine with EVEN row heights, but with ODD row heights it skips a blank line of pixels every two rows.
Example images below.
Summary:
- With integer scaling (e.g. 100%, 200%) -- all is fine. No visual errors.
- With NON-integer scaling (e.g. 150%):
-- If row height is an even number of pixels: all is fine
-- If row height is an odd number of pixels: skips a line of pixels every two rows
Expected behavior
List rows placed contiguously on top of each other, with no skipped pixel rows between (row ends drawing on line Y, next row begins drawing on Y+1 in all cases).
Actual behavior
With odd row height and non-integer Windows scaling, every two rows the list "hiccups" and starts drawing at (x, y+1) when it should be starting the row at (x, y).
Environment
This only happens in Windows, and only with non-integer windows content scaling.
(Which, as mentioned, is extremely common on modern large monitors -- 150% is actually labeled in Windows as the "recommended" setting for my 27" monitor.)
Additional details
Demo app used to produce screenshots:
import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body:
ScrollablePositionedList.builder(
itemBuilder:
(_, _) => Container(height: 24, color: Colors.green),
itemCount: 51,
)
),
);
}
}
Screenshots
Here are some examples of what works (sold green app window) and "bug" (horizontal lines in green app window).
The ones with the bug (horizontal lines) are all "odd row height + non-integer windows scaling."
Note: the "solid" green bars between gap-lines are actually TWO list row items, with zero pixels between them. It skips a pixel row every two rows.