user26547015
user26547015

Reputation: 3

Auto scale Flutter text widget based on widget width

I am building a Flutter app with a full screen page view.

Each page has an image and text at the bottom. I have some code to animate the page swipe animation where the next page feels like it's appearing from behind the current page.

Everything works great, except the next page has a smaller width than the current page which increases and fits the screen as the current page is being swiped away. When the next page has a smaller width, the inner text rearranges to accommodate the smaller width, which I don't want to happen.

Any way I can scale the text size based on width?

Here is the widget:

@override
  Widget build(BuildContext context) {
    launchURL(String readMoreURL) async {
      await FlutterWebBrowser.openWebPage(url: readMoreURL);
    }

    cardModel.read = true;

    return Container(
        color: Colors.white,
        child: Column(
          children: [
            Expanded(
              flex: 35,
              child: Image.network(
                cardModel.imageUrl,
                fit: BoxFit.cover,
                errorBuilder: (context, error, stackTrace) {
                  return Container(
                      color: const Color(0xFFF3D2BB),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          const Icon(
                            Icons.error_outline,
                            color: Color(0xFFB42D1E),
                            size: 50,
                          ),
                          const SizedBox(height: 10),
                          Text(
                            'Failed to load image',
                            style: GoogleFonts.sarabun(
                                fontSize: 16, color: const Color(0xFFB42D1E)),
                          ),
                        ],
                      ));
                },
              ),
            ),
            Expanded(
              flex: 65,
              child: Padding(
                padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    Text(
                      cardModel.title,
                      style: GoogleFonts.sarabun(
                          fontSize: 20, fontWeight: FontWeight.bold, height: 1.4),
                    ),
                    const SizedBox(height: 5),
                    Text(
                      cardModel.body,
                      style: GoogleFonts.sarabun(fontSize: 19, height: 1.4),
                    ),
                    const SizedBox(height: 10),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.start,
                      children: [
                        Text(
                          cardModel.formattedTimestamp,
                          style: const TextStyle(
                            fontSize: 14,
                            color: Colors.grey,
                          ),
                        ),
                        const Text(
                          " • ",
                          style: TextStyle(
                            fontSize: 14,
                            color: Colors.grey,
                          ),
                        ),
                        InkWell(
                          onTap: () => launchURL(cardModel.url),
                          child: const Text(
                            "Source",
                            style: TextStyle(
                                fontSize: 14,
                                color: Colors.blue,
                                decoration: TextDecoration.underline,
                                decorationColor: Colors.blue),
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ],
        ));
  }

Here is what this looks like: GIF

I tried wrapping the text column in FittedBox, but this is what it looks like: FittedBox

Upvotes: 0

Views: 59

Answers (2)

Imran Nawaz
Imran Nawaz

Reputation: 104

you can use auto_size_text package. It is convenient. Following is an example with custom widget function:

Widget buildDataText(String data,
{double scaleFactor = 1.06,
int? maxLines = 1,
FontWeight? fontWeight = FontWeight.w600}) {

  return AutoSizeText(
    data,
    textScaleFactor: scaleFactor,
    softWrap: true,
    style: TextStyle(fontWeight: fontWeight, color: Colors.white),
    maxLines: maxLines,
  );
}

Upvotes: 0

PurplePolyhedron
PurplePolyhedron

Reputation: 895

You could provide a width inside the FittedBox. If your text is always in a full screen you can use MediaQuery.sizeOf(context).width.

However, for best practice, use Transform.scale() to scale the page during swipe animation instead of changing its constraint.

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return FittedBox(
      child: SizedBox(
        width: MediaQuery.sizeOf(context).width,
        child: Text(
          "Flutter is an open source framework by Google for building beautiful, "
          "natively compiled, multi-platform applications from a single codebase.",
          style: TextStyle(fontSize: 40),
        ),
      ),
    );
  }
}

Upvotes: 0

Related Questions