arch-atlas

Add custom image to book details view

Presentation (Building the UI)

13:03

Summary

This lesson focuses on reusing an existing image widget for the book details screen and ensuring it scales responsively. The instructor demonstrates how an AspectRatio widget behaves when constrained by screen width, highlighting the difference between fixed and relative padding. By utilizing MediaQuery to apply padding as a percentage of the screen width, the image maintains its visual proportions across various device sizes. Finally, the widget is renamed to reflect its new, generalized role within the presentation layer, breaking its conceptual tie to just the home screen's featured list.

Key Ideas

  • Widget reusability reduces code duplication by repurposing existing components across different views.
  • AspectRatio widget automatically calculates its height based on the provided width constraint and the specified ratio.
  • Fixed pixel constraints (like horizontal padding) can break visual proportions when a layout is rendered on varying screen sizes.
  • MediaQuery provides the device's screen dimensions, allowing for accurate relative sizing calculations.
  • Relative padding (e.g., multiplying screen width by a decimal like 0.17) ensures the child widget scales proportionally across all devices.
  • Refactoring widget names to be generic (e.g., from FeaturedListViewItem to CustomBookImage) is necessary when a component is shared across multiple features.

Code Snippets

Book details body implementing responsive relative paddingdart
class BookDetailsViewBody extends StatelessWidget {
  const BookDetailsViewBody({super.key});

  @override
  Widget build(BuildContext context) {
    var width = MediaQuery.of(context).size.width;
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 30),
      child: Column(
        children: [
          const CustomBookDetailsAppBar(),
          Padding(
            padding: EdgeInsets.symmetric(horizontal: width * .17),
            child: const CustomBookImage(),
          ),
        ],
      ),
    );
  }
}
The refactored generic image widget (formerly FeaturedListViewItem)dart
class CustomBookImage extends StatelessWidget {
  const CustomBookImage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 2.7 / 4,
      child: Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(16),
          color: Colors.red,
          image: const DecorationImage(
            fit: BoxFit.fill,
            image: AssetImage(
              AssetsData.testImage,
            ),
          ),
        ),
      ),
    );
  }
}

My Notes

  • The instructor's approach to responsive scaling using MediaQuery.of(context).size.width * 0.17 is a quick and effective way to constrain an AspectRatio widget dynamically without hardcoding pixel values.
  • [Editor's note] As of Flutter 3.10+, you should prefer MediaQuery.sizeOf(context).width over MediaQuery.of(context).size.width. The older of(context) method binds the widget to the *entire* media query context, meaning the widget will needlessly rebuild if *anything* changes (like text scaling, device orientation, or the keyboard appearing). sizeOf(context) exclusively listens to size changes, making it more performant.
  • The decision to rename the widget from FeaturedListViewItem to CustomBookImage is a great modularization habit. Widgets should be named based on *what they are*, not *where they were originally used*, once they are promoted to shared components within the presentation layer.