Vintage appMaker의 Tech Blog

[Flutter] Layoutbuilder를 이용한 반응형 UI 본문

Source code or Tip/Flutter & Dart

[Flutter] Layoutbuilder를 이용한 반응형 UI

VintageappMaker 2022. 8. 15. 12:40

 

 

LayoutBuilder class - widgets library - Dart API

Builds a widget tree that can depend on the parent widget's size. Similar to the Builder widget except that the framework calls the builder function at layout time and provides the parent widget's constraints. This is useful when the parent constrains the

api.flutter.dev


 

Flutter에서는 반응형 UI를 처리하기 위해 LayouBuilder 위젯을 제공한다. 이 위젯을 사용화면 App의 전체크기를 변경이 있을 때마다 가져올 수 있다. 여기서 값을 가져오는 파라메터는 BoxConstraints 형의 데이터이다. 

LayoutBuilder(
  builder: (context, constraints) {
    // BoxConstraints인 constraints 정보를 이용하여
    // 현재 App의 전체크기를 구할 수 있다. 
    //constraints.maxWidth
    //constraints.maxHeight
    return child위젯;
  }
)

 

다음은 전체 전체소스이다. 

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      scrollBehavior: DeskScrollBehavior(),
      debugShowCheckedModeBanner: false,
      title: "LayoutBuilder",
      home: MainPage(),
    );
  }
}

class MainPage extends StatelessWidget {
  const MainPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(body: LayoutBuilder(builder: (context, constraints) {
      if (constraints.maxWidth > 550) {
        return _largePageWidget(constraints: constraints);
      } else {
        return _smallPageWidget(constraints: constraints);
      }
    }));
  }
}

Widget _buildHeader(String s,
    [double height = 100, double size = 30, Color c = Colors.black]) {
  return Container(
      width: double.infinity,
      height: height,
      color: c,
      child: Center(
          child: Text(
        s,
        style: TextStyle(fontSize: size, color: Colors.white),
      )));
}

Container _buildListView(List<Widget> items) {
  return Container(
    child: ListView.builder(
      physics: NeverScrollableScrollPhysics(),
      shrinkWrap: true,
      padding: const EdgeInsets.all(8),
      itemCount: items.length,
      itemBuilder: (BuildContext context, int index) {
        return items[index];
      },
    ),
  );
}

//
Widget _buildGridView(List<Widget> items) {
  return Container(
    child: GridView.builder(
        physics: NeverScrollableScrollPhysics(),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          mainAxisSpacing: 5,
          crossAxisSpacing: 5,
        ),
        itemCount: items.length,
        shrinkWrap: true,
        itemBuilder: (BuildContext context, int index) {
          return items[index];
        }),
  );
}

var _list_items = [
  for (var i = 0; i < 100; i++)
    ListTile(
        leading: Text("$i"),
        title: Row(
          children: [
            SizedBox(
                width: 100,
                height: 100,
                child: Image.network(
                    fit: BoxFit.fill,
                    "https://i.ytimg.com/vi/WuJ2xYlFyyY/hqdefault.jpg")),
            SizedBox(
              width: 8,
            ),
            Flexible(
              child: Container(
                padding: EdgeInsets.all(8),
                child: Text(
                  softWrap: false,
                  overflow: TextOverflow.ellipsis,
                  maxLines: 1,
                  "Ultima 5 - Warriors of Destiny",
                  style: TextStyle(fontSize: 18),
                ),
              ),
            ),
          ],
        ))
];

var _grid_items = [
  for (var i = 0; i < 10; i++) ...{
    Container(
        child: Padding(
      padding: const EdgeInsets.all(8.0),
      child: Image.network(
          fit: BoxFit.fill, "https://i.ytimg.com/vi/WuJ2xYlFyyY/hqdefault.jpg"),
    ))
  }
];

class _smallPageWidget extends StatelessWidget {
  BoxConstraints constraints;
  _smallPageWidget({Key? key, required this.constraints}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        _buildHeader("small layout", 50, 18),
        Expanded(
            child: SingleChildScrollView(
                physics: AlwaysScrollableScrollPhysics(),
                child: _buildListView(_list_items)))
      ],
    );
  }
}

class _largePageWidget extends StatelessWidget {
  BoxConstraints constraints;

  _largePageWidget({Key? key, required this.constraints}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        _buildHeader("large layout"),
        Expanded(
            child: SingleChildScrollView(
                physics: AlwaysScrollableScrollPhysics(),
                child: _buildGridView(_grid_items)))
      ],
    );
  }
}

// 웹과 desktop에서 모바일처럼 터치 스크롤 지원하기 위함
class DeskScrollBehavior extends MaterialScrollBehavior {
  @override
  Set<PointerDeviceKind> get dragDevices => {
        PointerDeviceKind.touch,
        PointerDeviceKind.mouse,
      };
}

 

Comments