flutter icon indicating copy to clipboard operation
flutter copied to clipboard

Antialiasing behaviour when same-colour

Open radzish opened this issue 7 years ago • 97 comments

Latest status update: https://github.com/flutter/flutter/issues/14288#issuecomment-1890250258; some work around suggestions: https://github.com/flutter/flutter/issues/14288#issuecomment-1026332976


Steps to Reproduce

Following source code:

import 'package:flutter/material.dart';

const Color color = const Color.fromARGB(255, 100, 100, 100);

void main() =>
    runApp(
      new Container(
        color: const Color.fromARGB(255, 0, 0, 0),
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.end,
          textDirection: TextDirection.ltr,
          children: [
            new Expanded(
              child: new Container(
                color: color,
              ),
            ),
            new Expanded(
              child: new Container(
                color: color,
              ),
            ),
            new Expanded(
              child: new Container(
                color: color,
              ),
            ),
            new Expanded(
              child: new Container(
                color: color,
              ),
            ),
            new Expanded(
              child: new Container(
                color: color,
              ),
            ),
            new Expanded(
              child: new Container(
                color: color,
              ),
            ),
            new Expanded(
              child: new Container(
                color: color,
              ),
            ),
          ],
        ),
      ),
    );

produces following result:

Looks like background of the container is popping out and we see vertical lines. That should not be the case as all children of the row are Expanded and thus should fill the whole area. If we remove one child lines are gone.

Logs

Launching lib/main.dart on Android SDK built for x86 in debug mode...
Initializing gradle...
Resolving dependencies...
Running 'gradlew assembleDebug'...
Built build/app/outputs/apk/app-debug.apk (22.4MB).
I/FlutterActivityDelegate( 8398): onResume setting current activity to this
D/EGL_emulation( 8398): eglMakeCurrent: 0xaad2c640: ver 3 1 (tinfo 0xa057c5b0)
E/eglCodecCommon( 8398): glUtilsParamSize: unknow param 0x000082da
E/eglCodecCommon( 8398): glUtilsParamSize: unknow param 0x000082da
E/eglCodecCommon( 8398): glUtilsParamSize: unknow param 0x00008cdf
E/eglCodecCommon( 8398): glUtilsParamSize: unknow param 0x00008cdf
E/eglCodecCommon( 8398): glUtilsParamSize: unknow param 0x00008824
E/eglCodecCommon( 8398): glUtilsParamSize: unknow param 0x00008824
D/        ( 8398): HostConnection::get() New Host Connection established 0xa31a3640, tid 8416
D/EGL_emulation( 8398): eglMakeCurrent: 0xaad2c640: ver 3 1 (tinfo 0xa3183790)
D/EGL_emulation( 8398): eglMakeCurrent: 0xaad2c760: ver 3 1 (tinfo 0xa057cc10)
Syncing files to device Android SDK built for x86...

Flutter Doctor

[✓] Flutter (on Linux, locale en_US.UTF-8, channel master)
    • Flutter version unknown at <path_to_flutter>
    • Framework revision 5ae770345a (3 days ago), 2018-01-23 13:46:14 -0800
    • Engine revision 171d032f86
    • Tools Dart version 2.0.0-dev.16.0
    • Engine Dart version 2.0.0-edge.93d8c9fe2a2c22dc95ec85866af108cfab71ad06

[✓] Android toolchain - develop for Android devices (Android SDK 27.0.3)
    • Android SDK at <path_to_android>
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-27, build-tools 27.0.3
    • ANDROID_HOME = <path_to_android>
    • Java binary at: <path_to_android-studio>/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-915-b01)

[✓] Android Studio (version 3.0)
    • Android Studio at <path_to_android-studio>
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-915-b01)

[✓] Connected devices
    • Android SDK built for x86 • emulator-5554 • android-x86 • Android 8.1.0 (API 27) (emulator)

radzish avatar Jan 26 '18 12:01 radzish

Another example (I believe it is somehow related: )

import 'package:flutter/material.dart';

const Color grey = const Color.fromARGB(255, 100, 100, 100);
const Color black = const Color.fromARGB(255, 0, 0, 0);

void main() =>
    runApp(
      new Container(
        color: grey,
        child: new Center(
          child: new Container(
            width: 151.0,
            height: 151.0,
            color: black,
            child: new Container(
              color: grey,
            ),
          ),
        ),
      ),
    );

We should not see border here. If widht/height are changed to 150.0, square is gone.

radzish avatar Jan 26 '18 12:01 radzish

This is normal behaviour. What's happening is that the boxes are not quite aligned with pixel boundaries, so there's some anti-aliasing happening on the boundaries, which involves transparency, which means that for those pixels the two grays are overlapping and looking darker.

As a general rule when doing anti-aliasing you want to avoid putting identically-coloured boxes adjacent or over each other unless you can guarantee physical pixel alignment.

Alternatively, you can use saveLayer (or RepaintBoundary) to cause a bunch of paint operations to get merged into one and composited as one. Not sure that that would help in these cases specifically but it is a tool that can be useful in this kind of situation.

Hixie avatar Jan 29 '18 20:01 Hixie

This is not boxes overlapping, but rather spare space between boxes, so color of background is popping up. I was changing background to different color and this color was popping out.

radzish avatar Jan 30 '18 11:01 radzish

Root cause is that boxes can not be aligned with physical pixels. I would not call it "normal", I would rather call it "expected". On android similar (semantically) case is handled properly:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:background="#000000"
    tools:context="com.radzish.android_lines_bug.MainActivity">

    <FrameLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:background="#646464"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:background="#646464"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:background="#646464"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:background="#646464"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:background="#646464"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:background="#646464"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:background="#646464"
        android:layout_height="match_parent"/>

</LinearLayout>

So I think flutter should improve in this case. The only workaround I found for me at the moment is sizing children manually like this:

    int CHILDREN_COUNT = 7;
    List<Widget> children = new List(CHILDREN_COUNT);

    MediaQueryData mediaQueryData = MediaQuery.of(context);
    int physicalWidth = (mediaQueryData.size.width * mediaQueryData.devicePixelRatio).floor();

    for (int i = 0, pixelsLeft = physicalWidth; i < CHILDREN_COUNT; i++) {
      int columnWidth = (pixelsLeft / (CHILDREN_COUNT - i)).floor();

      children[i] = new Container(
        width: columnWidth / mediaQueryData.devicePixelRatio,
        color: color,
      );

      pixelsLeft -= columnWidth;
    }

radzish avatar Feb 22 '18 11:02 radzish

There are also

  • #15035
  • #17084
  • #13675
  • #25429

zoechi avatar Dec 17 '18 14:12 zoechi

@radzish what is Android doing to avoid the problem?

Hixie avatar Feb 15 '19 21:02 Hixie

These comments have suggestions for things to put in documentation: https://github.com/flutter/flutter/issues/14288#issuecomment-361375791 https://github.com/flutter/flutter/issues/17084#issuecomment-385718108 https://github.com/flutter/flutter/issues/15035#issuecomment-370028740

Hixie avatar Feb 15 '19 21:02 Hixie

Any updates here? Because this is very annoying(( Or any examples how to use saveLayer or RepaintBoundary?

DenisBogatirov avatar Jul 18 '19 16:07 DenisBogatirov

Any updates here?

droplet-js avatar Nov 07 '19 01:11 droplet-js

Any updates here?

I have the problem too :(

blackraven96 avatar Jan 08 '20 22:01 blackraven96

Hi @blackraven96 the easiest workaround to this problem is to avoid using the same background color on adjacent elements, but use a background color for the whole list (or multi-child widget).

import 'package:flutter/material.dart';

void main() =>
    runApp(
        Container(
            color: Colors.white,
            child: Column(
                children: <Widget>[
                    Container(
                        child: Text("Item 1"),
                    ),
                    Container(
                        child: Text("Item 2"),
                    ),
                ],
            ),
        ),
    );

wallforfry avatar Jan 08 '20 22:01 wallforfry

I hope this problem can be solved soon

beiger avatar Mar 17 '20 10:03 beiger

I'm new to Flutter and I faced really quickly with this issue. I need to render a NxN grid of squares and the gaps between cells is quite annoying. Until there is a fix or a better workaround I'm using this delegate for CustomSingleChildLayout that removes the minimum number of pixels to avoid the gaps.

class GridFix extends SingleChildLayoutDelegate {
  GridFix(this.size, this.mediaQueryData);

  final int size;
  final MediaQueryData mediaQueryData;

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    var dpr = mediaQueryData.devicePixelRatio;
    var width = (((constraints.maxWidth * dpr) ~/ size) * size) / dpr;
    var height = (((constraints.maxHeight * dpr) ~/ size) * size) / dpr;
    return BoxConstraints.tightFor(width: width, height: height);
  }

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    return Offset(
      ((size.width - childSize.width) / 2).floorToDouble(),
      ((size.height - childSize.height) / 2).floorToDouble(),
    );
  }

  @override
  bool shouldRelayout(GridFix oldDelegate) {
    return oldDelegate.size != size;
  }
}

Then within the layout I use it like this:

return AspectRatio(
  aspectRatio: 1,
  child: CustomSingleChildLayout(
    delegate: GridFix(size, MediaQuery.of(context)),
    child: /* insert content here */
  ),
);

Of course this solution is specific for this case of a square grid and it works because I can spare some pixels around without affecting the layout too much. Again, I'm new to Flutter so I'm open to improvements or suggestions.

At the end I think Flutter layouts could always (or optionally) round the calculated size and offsets to the nearest physical pixel to to avoid this issue.

waj avatar Apr 05 '20 19:04 waj

Please also check some workaround discussions in https://github.com/flutter/flutter/issues/25009

liyuqian avatar Apr 08 '20 19:04 liyuqian

testing the code above the issue still occurs with the latest master

screenshot

image

doctor
[✓] Flutter (Channel master, 1.21.0-6.0.pre.38, on Mac OS X 10.15.5 19F101, locale en-GB)
    • Flutter version 1.21.0-6.0.pre.38 at /Users/nevercode/development/flutter_master
    • Framework revision 8e0eee9008 (7 hours ago), 2020-07-26 23:38:01 -0700
    • Engine revision 626244a72c
    • Dart version 2.9.0 (build 2.9.0-21.0.dev a3815b6590)


[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at /Users/nevercode/Library/Android/sdk
    • Platform android-29, build-tools 29.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.5)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.5, Build version 11E608c
    • CocoaPods version 1.9.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 46.0.2
    • Dart plugin version 193.7361
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] VS Code
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.12.2

[✓] Connected device (3 available)
    • macOS (desktop)  • macos      • darwin-x64     • Mac OS X 10.15.5 19F101
    • Web Server (web) • web-server • web-javascript • Flutter Tools
    • Chrome (web)     • chrome     • web-javascript • Google Chrome 84.0.4147.89

• No issues found!

iapicca avatar Jul 27 '20 13:07 iapicca

In the meantime, I found a very simple workaround. It has a downside, though: it doesn't work 100% time of scrolling... :/

Just add this to each tile Container in the GridView/SliverGrid:

decoration: BoxDecoration(
              color: Colors.black,
              borderRadius:
                  BorderRadius.only(topRight: Radius.circular(1)),
            ),

Before (without the rounded corner)

Captura de pantalla 2020-08-04 a las 14 57 21

After

Captura de pantalla 2020-08-04 a las 14 53 03

tomasbaran avatar Aug 04 '20 13:08 tomasbaran

Never mind my previous workaround since it doesn't work 100%.

@dhawalmehta22 found a fix (see original post: https://github.com/flutter/flutter/issues/25009) that works most of the time, although this doesn't work at all time, either :(

Just wrap the problematic container with another container and add this to the parenting container:

decoration: BoxDecoration(
             color: Colors.black, //the color of the main container
             border: Border.all(
               //apply border to only that side where the line is appearing i.e. top | bottom | right | left.
               width: 2.0, //depends on the width of the unintended line
               color: Colors.black,
             ),
           ),

tomasbaran avatar Aug 04 '20 19:08 tomasbaran

Is there an official solution to this problem ?

dashixiong91 avatar Sep 17 '20 01:09 dashixiong91

Let me add that this is not a problem of same color. I get the same result when trying to align multiple Positioned in a stack with different colors the moment the tile size isn't a full pixelsize you get this here:

grafik

Altough the y values of top+hight is the same as the next top value at some of these bounderies you have a gap where the black backgound is shining though.

this is the code:

class CheckerBoard extends StatelessWidget {
  const CheckerBoard({
    Key key,
    @required this.tileSize,
  }) : super(key: key);

  final double tileSize;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        for (var x = 0; x < 20; x++)
          for (var y = 0; y < 20; y++)
            Positioned(
              top: y * tileSize,
              left: x * tileSize,
              width: tileSize,
              height: tileSize,
              child: ColoredTile(
                indexX: x,
                indexY: y,
                top: y * tileSize,
                height: tileSize,
              ),
            )
      ],
    );
  }
}

class ColoredTile extends StatelessWidget {
  const ColoredTile({
    Key key,
    @required this.indexX,
    @required this.indexY,
    this.top,
    this.height,
  }) : super(key: key);

  final int indexX;
  final int indexY;
  final double top;
  final double height;

  @override
  Widget build(BuildContext context) {
    Color color;
    if (indexX.isEven && indexY.isEven) {
      color = Colors.blue;
    }
    if (indexX.isEven && indexY.isOdd) {
      color = Colors.red;
    }
    if (indexX.isOdd && indexY.isEven) {
      color = Colors.green;
    }
    if (indexX.isOdd && indexY.isOdd) {
      color = Colors.orange;
    }

    final m = MediaQuery.of(context);
    return Container(
      // clipBehavior: Clip.hardEdge,
      decoration: BoxDecoration(
        color: color,
      ),
//      child: Image.network('https://picsum.photos/256'),
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Stack(
          children: [
            Align(
              alignment: Alignment.topCenter,
              child: Text(
                'Top: ${top * m.devicePixelRatio} \n Height: ${height * m.devicePixelRatio}',
                style: TextStyle(color: Colors.black, fontSize: 12),
              ),
            ),
            Align(
              alignment: Alignment.bottomCenter,
              child: Text(
                'Top+Hight: ${(top + height) * m.devicePixelRatio}',
                style: TextStyle(color: Colors.black, fontSize: 12),
              ),
            ),
            Align(
              alignment: Alignment.center,
              child: Text(
                '$indexX/$indexY',
                style: TextStyle(color: Colors.black),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

this happens on Windows and Android. with latests master 1.26.0-2.0.pre.222

escamoteur avatar Jan 07 '21 18:01 escamoteur

Never mind my previous workaround since it doesn't work 100%.

@dhawalmehta22 found a fix (see original post: #25009) that works most of the time, although this doesn't work at all time, either :(

Just wrap the problematic container with another container and add this to the parenting container:

decoration: BoxDecoration(
             color: Colors.black, //the color of the main container
             border: Border.all(
               //apply border to only that side where the line is appearing i.e. top | bottom | right | left.
               width: 2.0, //depends on the width of the unintended line
               color: Colors.black,
             ),
           ),

Tried my solution in several projects and it worked perfectly.! Well, Working around is the only way till flutter resolves this bug.

dhawalmehta22 avatar Jan 08 '21 20:01 dhawalmehta22

@dhawalmehta22 It may have worked on certain resolutions. As I say it does work in some cases; however, I can assure you it doesn't work on all resolutions. If I remember correctly, I was figured it out it by changing the window size of a browser on my macOS—that way you can see when the bug happens.

tomasbaran avatar Jan 13 '21 15:01 tomasbaran

Reproduces on various platforms - Android, Web Windiws, Desktop Windows

code sample
import 'package:flutter/material.dart';

Future<void> main() async {
  runApp(
    MaterialApp(
      home: Scaffold(
        body: CustomPaint(
          painter: MyCustomPainter(),
          child: SizedBox.expand(),
        ),
      ),
    ),
  );
}

class MyCustomPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    int tilesInWidth = 20;
    int tilesInHeight = 25;
    double tileSize = 16.0;

    canvas.translate(1, 1); // if you remove this it looks fine

    for (int x = 0; x < tilesInWidth; x++) {
      for (int y = 0; y < tilesInHeight; y++) {
        canvas.drawRect(
          Rect.fromLTWH(x * tileSize, y * tileSize, tileSize, tileSize),
          Paint()..color = Colors.blue,
        );
      }
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
flutter doctor -v
[✓] Flutter (Channel stable, 1.22.5, on macOS 11.1 20C69 darwin-x64, locale en-GB)
    • Flutter version 1.22.5 at /Users/tahatesser/Code/flutter_stable
    • Framework revision 7891006299 (6 weeks ago), 2020-12-10 11:54:40 -0800
    • Engine revision ae90085a84
    • Dart version 2.10.4

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Volumes/Extreme/SDK
    • Platform android-30, build-tools 30.0.3
    • ANDROID_HOME = /Volumes/Extreme/SDK
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.3)
    • Xcode at /Volumes/Extreme/Xcode.app/Contents/Developer
    • Xcode 12.3, Build version 12C33
    • CocoaPods version 1.10.1

[!] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] VS Code (version 1.52.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.18.1

[✓] Connected device (1 available)
    • Taha’s iPhone (mobile) • 00008020-001059882212002E • ios • iOS 14.3

! Doctor found issues in 1 category.
[✓] Flutter (Channel beta, 1.25.0-8.3.pre, on macOS 11.1 20C69 darwin-x64, locale en-GB)
    • Flutter version 1.25.0-8.3.pre at /Users/tahatesser/Code/flutter_beta
    • Framework revision 5d36f2e7f5 (3 days ago), 2021-01-14 15:57:49 -0800
    • Engine revision 7a8f8ca02c
    • Dart version 2.12.0 (build 2.12.0-133.7.beta)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Volumes/Extreme/SDK
    • Platform android-30, build-tools 30.0.3
    • ANDROID_HOME = /Volumes/Extreme/SDK
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Volumes/Extreme/Xcode.app/Contents/Developer
    • Xcode 12.3, Build version 12C33
    • CocoaPods version 1.10.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] VS Code (version 1.52.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.18.1

[✓] Connected device (2 available)
    • Taha’s iPhone (mobile) • 00008020-001059882212002E • ios            • iOS 14.3
    • Chrome (web)           • chrome                    • web-javascript • Google Chrome 87.0.4280.141

• No issues found!
[✓] Flutter (Channel dev, 1.26.0-8.0.pre, on macOS 11.1 20C69 darwin-x64, locale en-GB)
    • Flutter version 1.26.0-8.0.pre at /Users/tahatesser/Code/flutter_dev
    • Framework revision b9d06fffb2 (10 days ago), 2021-01-07 18:36:48 -0800
    • Engine revision 42a8d4c681
    • Dart version 2.12.0 (build 2.12.0-179.0.dev)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Volumes/Extreme/SDK
    • Platform android-30, build-tools 30.0.3
    • ANDROID_HOME = /Volumes/Extreme/SDK
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.3)
    • Xcode at /Volumes/Extreme/Xcode.app/Contents/Developer
    • Xcode 12.3, Build version 12C33
    • CocoaPods version 1.10.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] VS Code (version 1.52.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.18.1

[✓] Connected device (3 available)
    • Taha’s iPhone (mobile) • 00008020-001059882212002E • ios            • iOS 14.3
    • macOS (desktop)        • macos                     • darwin-x64     • macOS 11.1 20C69 darwin-x64
    • Chrome (web)           • chrome                    • web-javascript • Google Chrome 87.0.4280.141

• No issues found!
[✓] Flutter (Channel master, 1.26.0-2.0.pre.402, on macOS 11.1 20C69 darwin-x64, locale en-GB)
    • Flutter version 1.26.0-2.0.pre.402 at /Users/tahatesser/Code/flutter_master
    • Framework revision 2a188eeca3 (8 hours ago), 2021-01-17 19:27:00 -0800
    • Engine revision 609036f2bf
    • Dart version 2.12.0 (build 2.12.0-236.0.dev)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Volumes/Extreme/SDK
    • Platform android-30, build-tools 30.0.3
    • ANDROID_HOME = /Volumes/Extreme/SDK
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Volumes/Extreme/Xcode.app/Contents/Developer
    • Xcode 12.3, Build version 12C33
    • CocoaPods version 1.10.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] VS Code (version 1.52.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.18.1

[✓] Connected device (3 available)
    • Taha’s iPhone (mobile) • 00008020-001059882212002E • ios            • iOS 14.3
    • macOS (desktop)        • macos                     • darwin-x64     • macOS 11.1 20C69 darwin-x64
    • Chrome (web)           • chrome                    • web-javascript • Google Chrome 87.0.4280.141

• No issues found!

TahaTesser avatar Jan 18 '21 11:01 TahaTesser

Having the same issue, 2 containers in column with same color showing a really fine line between them, manually setting border widths didn't help.

riekusr avatar Feb 04 '21 08:02 riekusr

I had same issue some time ago with Row, I also was impelementing calendar for range picking. I found out that main problem was that width of container was not divisible by number of columns. So I did a small trick: added padding in outer container, so that width of container would be divisible by number of columns. Here is the example:

final numberOfColumns = 7;
final screenWidth = MediaQuery.of(context).size.width; // In my case row was full width of scree

final remainder = screenWidth % numberOfColumns;
var padded = screenWidth - remainder; // padded is width that is divisible by numberOfColumns

// This while is needed for padding to be not less than 30 pixels (by design). You may not doing this, if you don't need extra padding
while (screenWidth - padded < 30) {
  padded -= numberOfColumns; // subtract number of columns to keep padded divisible by columns
}

final containerPadding = screenWidth - padded; // compute padding

return Padding(
  padding: EdgeInsets.symmetrical(horizontal: containerPadding / 2), // MAIN LINE!
  child: Row(
    children: List.generate(numberOfColumns, (index) => Expanded(child: Container(color: Colors.red))),
  ),
);

sorokinDev avatar Feb 11 '21 20:02 sorokinDev

I have another simple example item height: 20.0 -> no problem item height: 20.1, 20.2, 20.3 -> gap without scroll + moving gap with scroll item height: 20.01, 20.0001 -> no gap without scroll + moving gap with scroll

https://user-images.githubusercontent.com/10491866/110145431-c4bf7d80-7e1c-11eb-85fb-6919e59b7f26.mp4

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        backgroundColor: Colors.white,
        body: SafeArea(
          child: SingleChildScrollView(
            child: Column(
              children: [
                buildListView(20),
                buildListView(20.1),
                buildListView(20.2),
                buildListView(20.3),
                buildListView(20.01),
                buildListView(20.001),
              ],
            ),
          ),
        ),
      ),
    );
  }

  ListView buildListView(double itemHeight) {
    return ListView.builder(
      shrinkWrap: true,
      padding: EdgeInsets.symmetric(vertical: 10),
      physics: NeverScrollableScrollPhysics(),
      itemCount: 10,
      itemBuilder: (context, index) => Container(
        height: itemHeight,
        color: Color(0xFF888888),
        child: Text('$itemHeight - $index'),
      )
    );
  }
}

wph144 avatar Mar 05 '21 16:03 wph144

Any update on this 2 years old issue? Ran into similar weirdness too: Code example: https://gist.github.com/Moonspeaker/0e8573ff6620a7e00b8f7b04937b51a1 This is how it looks on any flutter branch: https://www.youtube.com/watch?v=DDxu1NTkaMA&feature=youtu.be

obsolete-outdated avatar Mar 11 '21 19:03 obsolete-outdated

Reproducible on 2.0.4 https://github.com/flutter/flutter/issues/80330#issue-856510027

TahaTesser avatar Apr 14 '21 06:04 TahaTesser

Are there any plans to fix this or provide some recommended workarounds?

bartekpacia avatar Jul 05 '21 11:07 bartekpacia

I have another simple example item height: 20.0 -> no problem item height: 20.1, 20.2, 20.3 -> gap without scroll + moving gap with scroll item height: 20.01, 20.0001 -> no gap without scroll + moving gap with scroll

Screen_Recording_20210306-013814.mp4

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        backgroundColor: Colors.white,
        body: SafeArea(
          child: SingleChildScrollView(
            child: Column(
              children: [
                buildListView(20),
                buildListView(20.1),
                buildListView(20.2),
                buildListView(20.3),
                buildListView(20.01),
                buildListView(20.001),
              ],
            ),
          ),
        ),
      ),
    );
  }

  ListView buildListView(double itemHeight) {
    return ListView.builder(
      shrinkWrap: true,
      padding: EdgeInsets.symmetric(vertical: 10),
      physics: NeverScrollableScrollPhysics(),
      itemCount: 10,
      itemBuilder: (context, index) => Container(
        height: itemHeight,
        color: Color(0xFF888888),
        child: Text('$itemHeight - $index'),
      )
    );
  }
}

计算高度的时候使用以下代码可以解决这个问题 (itemHeight * WidgetsBinding.instance.window.devicePixelRatio).round() / WidgetsBinding.instance.window.devicePixelRatio

WangYng avatar Jul 08 '21 08:07 WangYng

@WangYng Thanks for workaround. This looks good for fixed height or known height. But my actual case is dynamic height items in listview. Additionally, I use package https://pub.dev/packages/responsive_framework which make entire screen scales (decimal point). It still looks that needs fundamental fix on flutter level.

wph144 avatar Jul 08 '21 09:07 wph144