Flutter——自适应设计

效果视频

Flutter——自适应设计

实体数据

实体类

class People{
  final String name;
  final String age;
  final String address;
  final String phone;
  final String picture;
  const People(this.name,this.age,this.address,this.phone,this.picture);
}

转为List

将集合Map中的数据转为List形式

final List<People> peoples = peopleMap.map((e) => People(
        e['name'].toString(),
        e['age'].toString(),
        e['address'].toString(),
        e['phone'].toString(),
        e['picture'].toString()))
    .toList(growable: false);

Map数据

下列一组Map数据是为啦实验这个Demo做的一组模拟数据

final List<Map<String,Object>> peopleMap =
    [
      {
        "name": "FranzLiszt",
        "age": "21",
        "sex": "male",
        "address": "湖南省xxxxxxxxxxxxxxx",
        "phone": "17311112222",
        "picture": "https://puui.qpic.cn/vstar_pic/0/name_77904_688t1467970955.jpg/0?max_age=7776000"
      },
      {
        "name": "Jack",
        "age": "19",
        "sex": "male",
        "address": "湖北省xxxxxxxxxxxxxxx",
        "phone": "1733334444",
        "picture": "https://puui.qpic.cn/vstar_pic/0/name_94722_688t1505976146.jpg/0?max_age=7776000"
      },
      {
        "name": "Peter",
        "age": "35",
        "sex": "male",
        "address": "北京市xxxxxxxxxxxxxxx",
        "phone": "17344445555",
        "picture": "https://puui.qpic.cn/media_img/0/854561579417059/0?max_age=7776000"
      },
      {
        "name": "Smith",
        "age": "45",
        "sex": "male",
        "address": "河南xxxxxxxxxxxxxxx",
        "phone": "17344556666",
        "picture": "https://puui.qpic.cn/media_img/0/932661658913960/0?max_age=7776000"
      },
      {
        "name": "Garcia",
        "age": "21",
        "sex": "female",
        "address": "天津市xxxxxxxxxxxxxxx",
        "phone": "17366778899",
        "picture": "https://puui.qpic.cn/media_img/0/955481577176312/0?max_age=7776000"
      },
      {
        "name": "Rodriguez",
        "age": "17",
        "sex": "male",
        "address": "河北省xxxxxxxxxxxxxxx",
        "phone": "17322334455",
        "picture": "https://puui.qpic.cn/media_img/0/1093271609034985/0?max_age=7776000"
      },
      {
        "name": "Wilson",
        "age": "38",
        "sex": "male",
        "address": "江苏省xxxxxxxxxxxxxxx",
        "phone": "17311223344",
        "picture": "https://puui.qpic.cn/vstar_pic/0/name_77904_688t1467970955.jpg/0?max_age=7776000"
      },
      {
        "name": "Jones",
        "age": "44",
        "sex": "male",
        "address": "浙江省xxxxxxxxxxxxxxx",
        "phone": "17377889900",
        "picture": "https://puui.qpic.cn/vstar_pic/0/name_77904_688t1467970955.jpg/0?max_age=7776000"
      },
      {
        "name": "Miller",
        "age": "18",
        "sex": "female",
        "address": "四川省xxxxxxxxxxxxxxx",
        "phone": "17323233434",
        "picture": "https://puui.qpic.cn/vstar_pic/0/name_77904_688t1467970955.jpg/0?max_age=7776000"
      },
      {
        "name": "Davis",
        "age": "55",
        "sex": "male",
        "address": "重庆市xxxxxxxxxxxxxxx",
        "phone": "17334345656",
        "picture": "https://puui.qpic.cn/vstar_pic/0/name_77904_688t1467970955.jpg/0?max_age=7776000"
      }
    ];

宽度自适应

通过LayoutBuilder组件构造两个布局,通过获取当前屏幕宽度大小,如果小于限定值则采用窄布局,反之,采用宽布局

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: LayoutBuilder(
        builder: (context,constraints){
          //maxWidth = 428.0
          if(constraints.maxWidth < 500){
            return const NarrowLayout();
          }else{
            return const WidthLayout();
          }
        },
      ),
    );
  }
 }

宽布局

通过采用Row布局,形成一个一行两列的排列,然后通过Expanded,去控制两列大小权重;左列为一个ListView列表,右列为点击左列Ietm回调的相关数据;其中需要注意的时左列personCallBack为一个回调方法,回调结果为当前被点击的Item实体类数据,然后做了一个setState刷新行为,将数据赋值给变量_person,让其方便展示右列数据

/// 假如屏幕宽度大于限定值后,采用此布局
/// 例如:当屏幕旋转后,此时宽度为之前的高度*/

class WidthLayout extends StatefulWidget {
  const WidthLayout({Key? key}) : super(key: key);

  @override
  State<WidthLayout> createState() => _WidthLayoutState();
}

class _WidthLayoutState extends State<WidthLayout> {
  People? _person;
  @override
  Widget build(BuildContext context) {
    return  Row(
      children: [
        Expanded(flex: 2,
          child: PeopleList(personCallBack: (person) => setState(() { _person = person;})),),
        Expanded(flex: 3,
          child: _person == null ? const Placeholder():PeopleDetail(person: _person!))
      ],
    );
  }
}
左列

左边展示一个联系人列表,并定义啦一个personCallBack接口,然后在Item的点击方法内实现了此方法,将此方法进行传递,联系上文,所描述的右列展示数据来源于此

class PeopleList extends StatelessWidget {
  final void Function(People) personCallBack;
  const PeopleList({Key? key,required this.personCallBack}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: peoples.length,
        itemBuilder: (context,index){
          return ListTile(
            title: Text(peoples[index].name,style: const TextStyle(fontSize: 18.0,fontWeight: FontWeight.bold)),
            subtitle: Text(peoples[index].age,style: const TextStyle(fontSize: 14.0,fontWeight: FontWeight.normal)),
            leading: const Icon(Icons.people_alt_outlined),
            onTap: (){personCallBack(peoples[index]);},
          );
        }
    );
  }
}
右列

右列先暂且不进行阐述,因为右列又对高度进行了自适应设计,具体内容放到后文的高度自适应中进行描述

class PeopleDetail extends StatelessWidget {
  final People person;
  const PeopleDetail({Key? key,required this.person}) : super(key: key);


  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context , constraints ) {
      if(constraints.maxHeight > 500){
        return _HeightLayout(person: person);
      }else{
        return _ShortLayout(person: person);
      }
     },
    );
  }
}

窄布局

宽布局是将两个页面放到了一个页面中,而窄布局是将其分为两个页面,通过Item点击方法进行路由传值进行展示

路由

左侧列表与上述宽布局列表代表一样,通过复用方法减少代码量;但是值得注意的是,在上述的宽布局图片展示中,右列并没有导航栏,而在窄布局的时候就产生导航栏,重点是在通过路由传值的时候,构造了Scaffold脚手架,并设置了一个导航栏,联系人详情页也是复用的,在声明的时候默认没有导航栏,所以在宽布局时,右侧没有导航栏

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

  @override
  Widget build(BuildContext context) {
    return PeopleList(personCallBack: (person) {
      Navigator.of(context).push(MaterialPageRoute(
          builder: (context) => Scaffold(
              appBar: AppBar(title: const Text('联系人详情')),
              body: PeopleDetail(person: person))));
    });
  }
}

高度自适应

通过LayoutBuilder组件构造两个布局,通过获取当前屏幕高度大小,如果小于限定值则采用短布局,反之,采用高布局

class PeopleDetail extends StatelessWidget {
  final People person;
  const PeopleDetail({Key? key,required this.person}) : super(key: key);


  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context , constraints ) {
      if(constraints.maxHeight > 500){
        return _HeightLayout(person: person);
      }else{
        return _ShortLayout(person: person);
      }
     },
    );
  }
}

高布局

当屏幕高度大于限定值时,图片、电话、地址按纵向排列

class _HeightLayout extends StatelessWidget {
  final People person;
  const _HeightLayout({Key? key,required this.person}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Image.network(person.picture,fit: BoxFit.cover,width: 100.0,height: 100.0),
          Text(person.phone,style: const TextStyle(fontSize: 14.0,fontWeight: FontWeight.normal)),
          Text(person.address,style: const TextStyle(fontSize: 16.0,fontWeight: FontWeight.bold))
        ],
      ),
    );
  }
}

低布局

当屏幕高度小于限定值时,图片与电话和地址呈横向排列,电话和地址呈纵向排列

class _ShortLayout extends StatelessWidget {
  final People person;
  const _ShortLayout({Key? key,required this.person}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        children: [
          Image.network(person.picture,fit: BoxFit.cover,width: 200.0,height: 200.0),
          Expanded(child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(person.phone,style: const TextStyle(fontSize: 14.0,fontWeight: FontWeight.normal)),
              Text(person.address,style: const TextStyle(fontSize: 16.0,fontWeight: FontWeight.bold))
            ],
          )
          )
        ],
      ),
    );
  }
}

在Flutter进行MacOS端开发时,如果加载网络图片显示异常,则需要添加网络权限,在macos->Runner->DebugProfile.entitlements中添加如下语句

<key>com.apple.security.network.client</key>
<true/>

猜你喜欢

转载自blog.csdn.net/News53231323/article/details/127753506
今日推荐