이번에는 데이터가 로딩될때 인디케이터 방식 대신 Shimmer 를 이용하여 로딩시 대기 화면을 구현해보겠습니다.
개발환경 : 윈도우11, 안드로이드 스튜디오, flutter 3.0.1
화면 구성은 아래와 같습니다.
필요한 패키지는 아래와 같습니다.
shimmer: ^2.0.0
./src/screens/home/items_page.dart 에 shimmer 및 SizeTransition 구현
FutureBuilder 를 이용하여 5초동안 shimmer 가 보여지고 이후에는 정상 데이터가 보여진다.
shimmer 가 보여지는 동안 animationController 를 이용하여 일부 컨테이너의 사이즈를 가변 시켰다.
// 메인 build 에 _shimmerListView 추가.
@override
Widget build(BuildContext context) {
// 사진 사이즈를 화면 비율에 맞춰서 비례적으로 주기 위해서 LayoutBuilder 사용함,
return LayoutBuilder(
builder: (context, constraints) {
Size size = MediaQuery.of(context).size;
final imgSize = size.width / 4;
return FutureBuilder(
future: Future.delayed(const Duration(seconds: 5)),
builder: (context, snapshot) {
return AnimatedSwitcher(
duration: const Duration(seconds: 1),
child: (snapshot.connectionState == ConnectionState.done)
? _listView(imgSize)
: _shimmerListView(imgSize),
);
});
},
);
}
// _shimmerListView 위젯 생성
Widget _shimmerListView(double imgSize) {
// BoxDecoration 에서 색상을 설정시, Container 에서는 색상정보를 제거해야 한다,
BoxDecoration containerDeco({required double radius}) {
return BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.circular(radius));
}
_containerSample({required double height, required double width, required double radius}) {
return Container(height: height, width: width, decoration: containerDeco(radius: radius));
}
return Shimmer.fromColors(
highlightColor: Colors.grey[100]!,
enabled: true,
baseColor: Colors.grey[300]!,
period: const Duration(seconds: 2),
child: ListView.separated(
padding: const EdgeInsets.all(padding_16),
separatorBuilder: (context, index) {
return const Divider(
thickness: 1,
color: Colors.black26,
height: padding_16 * 2 + 1,
indent: padding_16,
endIndent: padding_16,
);
},
itemCount: 10,
itemBuilder: (context, index) {
return SizedBox(
height: imgSize,
child: Row(
children: <Widget>[
_containerSample(height: imgSize, width: imgSize, radius: 12.0),
const SizedBox(width: padding_16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// 동일한 위젯을 호출하기 위해서는 키값이 필요하다
SizeTransitionAnimation(key: UniqueKey(), height: 14, width: 140, radius: 4),
const SizedBox(height: 8),
SizeTransitionAnimation(key: UniqueKey(), height: 12, width: 70, radius: 4),
const SizedBox(height: 8),
SizeTransitionAnimation(key: UniqueKey(), height: 14, width: 100, radius: 4),
Expanded(child: Container()),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizeTransitionAnimation(key: UniqueKey(), height: 14, width: 150, radius: 4),
],
),
],
),
),
],
),
);
},
),
);
}
// 새로운 에니메이션을 위한 클래스를 StatefulWidget 으로 생성.
class SizeTransitionAnimation extends StatefulWidget {
final double height;
final double width;
final double radius;
const SizeTransitionAnimation({
Key? key,
required this.height,
required this.width,
required this.radius,
}) : super(key: key);
@override
State<SizeTransitionAnimation> createState() => _SizeTransitionAnimationState();
}
class _SizeTransitionAnimationState extends State<SizeTransitionAnimation>
with SingleTickerProviderStateMixin {
late AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
// 에니메이션이 70 ~ 100% 사이로 움직이게 설정
lowerBound: 0.7,
// 에니메이션이 계속 반복
)..repeat(reverse: true);
late Animation<double> animation = CurvedAnimation(
parent: controller,
curve: Curves.easeInOut,
);
@override
void dispose() {
controller.dispose();
super.dispose();
}
BoxDecoration containerDeco({required double radius}) {
return BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
borderRadius: BorderRadius.circular(radius),
// Shimmer 때문에, 실제 gradient 는 동작하지 않음,
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.deepOrange,
Colors.deepPurple,
],
),
);
}
@override
Widget build(BuildContext context) {
return SizeTransition(
sizeFactor: animation,
axis: Axis.horizontal,
axisAlignment: 0.5,
child: Container(
height: widget.height,
width: widget.width,
decoration: containerDeco(radius: widget.radius),
),
);
}
}
'Flutter > 12 Clone 'Used Goods app'' 카테고리의 다른 글
[Flutter] Clone - 당근마켓21(userModel) (0) | 2022.08.03 |
---|---|
[Flutter] Clone - 당근마켓20(Firestore database) (0) | 2022.08.03 |
[Flutter] Clone - 당근마켓18(Phone Auth) (0) | 2022.07.28 |
[Flutter] Clone - 당근마켓17(firebase 환경설정 테스트) (0) | 2022.07.27 |
[Flutter] Clone - 당근마켓16(Firebase 환경설정) (0) | 2022.07.27 |