Flutter鸿蒙开发指南(六):首页轮播图渲染
本文介绍了使用Flutter实现轮播图功能的开发过程。主要内容包括:1)使用carousel_slider插件搭建轮播图组件;2)通过BannerItem类定义轮播图数据结构;3)实现图片自适应屏幕宽度和自动播放功能;4)使用Stack布局整合轮播图、搜索框和导航条。开发过程中重点解决了图片尺寸适配问题,通过MediaQuery获取屏幕宽度,并设置viewportFraction为1实现全屏显示。
一、轮播图实现思路
轮播图的组成由:上面搜索框,中间轮播图,下面导航条。搜索框和导航条是叠加在最外层组件。要用Stack,Stack用轮播图,搜索框和导航条通过position的定位固定位置。Stack必须配合position成对出现。
1.1 使用轮播图组件
flutter pub add carousel_slider

看到"carousel_slider"这个插件有版本号,说明已经成功了。

1.2 编写轮播图相关代码
网络图片地址如下,这个用于测试:
https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/1.jpg
https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/2.png
https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/3.jpg
定义轮播图数据对象类型:lib/viewmodels/home.dart代码
class BannerItem{
String id;
String imgUrl;
BannerItem({required this.id, required this.imgUrl});
}
//每一个轮播图具体类型
lib/pages/Home/index.dart代码
import 'package:flutter/cupertino.dart';
import 'package:qing_mall/components/Home/HmCategory.dart';
import 'package:qing_mall/components/Home/HmHot.dart';
import 'package:qing_mall/components/Home/HmMoreList.dart';
import 'package:qing_mall/components/Home/HmSlider.dart';
import 'package:qing_mall/components/Home/HmSuggestion.dart';
import 'package:qing_mall/viewmodels/home.dart';
class HomeView extends StatefulWidget {
const HomeView({super.key});
@override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final List<BannerItem> _bannerList = [
BannerItem(
id: "1",
imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/1.jpg",
),
BannerItem(
id: "2",
imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/2.png",
),
BannerItem(
id: "3",
imgUrl: "https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/meituan/3.jpg",
),
];
//获取滚动容器的内容
List<Widget> _getScrollChildren() {
return [
//包裹普通widget的sliver家族的组件内容
SliverToBoxAdapter(child: HmSlider(bannerList: _bannerList)), //轮播图组件
//放置分类组件
SliverToBoxAdapter(child: SizedBox(height: 10)),
//SliverGrid SliverList指南纵向排列
SliverToBoxAdapter(child: HmCategory()), //分类组件
SliverToBoxAdapter(child: SizedBox(height: 10)),
SliverToBoxAdapter(child: HmSuggestion()), //推荐组件
SliverToBoxAdapter(child: SizedBox(height: 10)),
//Flex和Expanded配合起来可以均分比例
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Flex(
direction: Axis.horizontal,
children: [
Expanded(child: HmHot()),
SizedBox(
width: 10,
),
Expanded(child: HmHot()),
],
)),
),
SliverToBoxAdapter(child: SizedBox(height: 10)),
HmMorelist(), //无限滚动列表
];
}
@override
Widget build(BuildContext context) {
//CustomScrollview要求:必须是sliver家族的内容
return CustomScrollView(slivers: _getScrollChildren());
}
}
lib/components/Home/HmSlider.dart代码
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:qing_mall/viewmodels/home.dart';
class HmSlider extends StatefulWidget {
//父传子
final List<BannerItem> bannerList;
HmSlider({Key? key, required this.bannerList}) : super(key: key);
@override
State<HmSlider> createState() => _HmSliderState();
}
class _HmSliderState extends State<HmSlider> {
Widget _getSlider(){
//返回轮播图插件
//根据数据渲染的不同的轮播选项
return CarouselSlider(items: List.generate(widget.bannerList.length, (int index){
return Image.network(widget.bannerList[index].imgUrl);
}), options: CarouselOptions());
}
@override
Widget build(BuildContext context) {
//Stack里面放轮播图 再盖上搜索框 指示灯导航
return Stack(
children: [
//第一个放轮播图
_getSlider()
],
);
// return Container(
// color: Colors.blue,
// height: 300,
// alignment: Alignment.center,
// child:
// Text('轮播图', style: TextStyle(color: Colors.white, fontSize: 20)));
}
}
运行鸿蒙端,可以看到轮播图已经出来了,但是效果不太正常。因为还没有给图片设置宽度以及图片的自适应

在开发中,高度和宽度一般是不能写死的。何为写死?比如宽度直接设置为600,高度设置为800就是写死,当手机屏幕分辨率不同的时候会导致异常。所以我们需要动态获取,关键代码:
//在Flutter中获取屏幕宽度的方法:媒体查询对象: MediaQuery
final double screenWidth = MediaQuery.of(context).size.width; //屏幕宽度
还需要视口,视口默认是0.8,关键代码:
//CarouselOptions中有一个视口占比: viewportFraction:
viewportFraction:1
改变lib/components/Home/HmSlider.dart代码
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:qing_mall/viewmodels/home.dart';
class HmSlider extends StatefulWidget {
//父传子
final List<BannerItem> bannerList;
HmSlider({Key? key, required this.bannerList}) : super(key: key);
@override
State<HmSlider> createState() => _HmSliderState();
}
class _HmSliderState extends State<HmSlider> {
Widget _getSlider(){
//在Flutter中获取屏幕宽度的方法:媒体查询对象: MediaQuery
final double screenWidth = MediaQuery.of(context).size.width; //屏幕宽度
//返回轮播图插件
//根据数据渲染的不同的轮播选项
return CarouselSlider(items: List.generate(widget.bannerList.length, (int index){
return Image.network(widget.bannerList[index].imgUrl,
fit: BoxFit.cover,
width: screenWidth,);
}), options: CarouselOptions(
//CarouselOptions中有一个视口占比: viewportFraction:
viewportFraction:1
));
}
@override
Widget build(BuildContext context) {
//Stack里面放轮播图 再盖上搜索框 指示灯导航
return Stack(
children: [
//第一个放轮播图
_getSlider()
],
);
// return Container(
// color: Colors.blue,
// height: 300,
// alignment: Alignment.center,
// child:
// Text('轮播图', style: TextStyle(color: Colors.white, fontSize: 20)));
}
}
运行效果如下,可以看到屏幕已经占满了。但是现在轮播图没有自动播放,我们现在需要实现自动播放

1.3 实现轮播图自动播放
设置为自动播放,只需要添加一个属性即可,关键代码:
autoPlay: true
默认3秒钟执行一次,运行即可看到3秒后自动播放。
调整播放间距代码:
//默认3秒
autoPlayInterval: Duration(seconds: 5),
HmSlider.dart完整代码如下:
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:qing_mall/viewmodels/home.dart';
class HmSlider extends StatefulWidget {
//父传子
final List<BannerItem> bannerList;
HmSlider({Key? key, required this.bannerList}) : super(key: key);
@override
State<HmSlider> createState() => _HmSliderState();
}
class _HmSliderState extends State<HmSlider> {
Widget _getSlider() {
//在Flutter中获取屏幕宽度的方法:媒体查询对象: MediaQuery
final double screenWidth = MediaQuery.of(context).size.width; //屏幕宽度
//返回轮播图插件
//根据数据渲染的不同的轮播选项
return CarouselSlider(
items: List.generate(widget.bannerList.length, (int index) {
return Image.network(
widget.bannerList[index].imgUrl,
fit: BoxFit.cover,
width: screenWidth,
);
}),
options: CarouselOptions(
//CarouselOptions中有一个视口占比: viewportFraction:
//高度默认300
height: 300,
//调整播放间距
autoPlayInterval: Duration(seconds: 5),
viewportFraction: 1,
autoPlay: true));
}
@override
Widget build(BuildContext context) {
//Stack里面放轮播图 再盖上搜索框 指示灯导航
return Stack(
children: [
//第一个放轮播图
_getSlider()
],
);
// return Container(
// color: Colors.blue,
// height: 300,
// alignment: Alignment.center,
// child:
// Text('轮播图', style: TextStyle(color: Colors.white, fontSize: 20)));
}
}

二、总结
第一步声明了BannerItem,为什么要声明?
使用Map<String,dynamic>这种类型也行,但是用class类型会更加明确。之前的Tab就是使用Map<String,dynamic>来实现。用class,可以通过.的形式,.不出来就报错。两种选择:一种更加灵活,但是不容易察觉报错的写法,另一种是类型明确。
第二步在Home/index.dart声明了三张图片的数据,通过构造函数的方式传入id和imageurl地址。如果后面要缓存接口,只需要把接口重新删除,再对_bannerList重新赋值就可以了。
第三步声明完数据后。把数据传递给了HmSlider,通过父传子组件接收这个数据,接收之后在对应的内CarouselSider。还需要尺寸适配、适应屏幕宽度、以及是否自动播放,把原来的Container放成了Stack布局。因为后续需要实现指示灯导航和搜索UI结构。
完成本教程后,记得提交代码:

最后,欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)