Flutter 中的 Shimmer 动画效果

老孟Flutter

共 13475字,需浏览 27分钟

 ·

2021-07-15 14:41


加载时间在应用程序改进中是不可避免的。从用户体验 (UX) 的角度来看,主要是向您的用户展示正在加载。处理向用户传递信息正在加载的一种主流方法是在不准确的加载物质类型的形状上显示带有微光动画的铬色调。

在在这篇博客中,我们将探索 Flutter 中的 Shimmer 动画效果。我们将看到如何实现微光动画效果的演示程序,并在您的 Flutter 应用程序中使用shimmer包展示加载动画效果。

什么是微光动画效果?

Shimmer 用于在应用程序中从服务器加载内容时添加精彩的动画。这使 UI 看起来更具响应性。它可以很好地被利用,而不是传统的 ProgressBar 或 Flutter 结构中可访问的常见loading。

通常,在我们打开应用程序的任何时候,我们都会看到具有动画的loading。它演示了应用程序从服务器或本地数据库加载信息。有多种方法可以显示这种效果。在这种情况下,我们通常会在加载信息后对与第一个小部件完全相似的小部件进行动画处理。

此演示视频展示了如何在颤动中创建微光动画效果。它展示了如何在 Flutter应用程序中使用shimmer包来实现微光动画效果。它显示代码何时成功运行,然后显示内容正在从虚拟数据加载是带有持续时间的微光动画效果,然后加载完成然后内容将显示在您的设备上。

特性

微光动画效果有一些属性:

  • **baseColor:**显示在 Widget 上的 Shimmer 的基本颜色。这种颜色是必不可少的,因为子小部件将采用这种颜色。
  • highlightColor: Highlight Color 是提供微光般效果的颜色。这种颜色继续在子小部件上波动,并产生微光效果。
  • child: Child 拥有创建 ShimmerEffect 所需的任何小部件。可以是文本小部件或复杂的设计,并且创建 ShimmerEffect 没有任何问题。
  • **direction:**您可以从左到右、从右到左、从开始到结束或从底到顶调整微光高光颜色的方向,为此,您只需传递具有确定方向的 ShimmerDirection。
  • **period:**它控制微光效果的速度。默认值为 1500 毫秒。

实现

  1. 添加依赖

    shimmer: ^2.0.0
  2. 导入

    import 'package:shimmer/shimmer.dart';
  3. 执行 flutter packages get

创建一个 movie_model.dart 文件

class MovieModel {
  final String urlImg;
  final String title;
  final String detail;


  const MovieModel({required this.urlImg, 
    required this.title, 
    required this.detail});
}

我们将创建一个类**MovieModel。**在这个类中,我们将创建三个最终字符串,分别是 urlImg、title 和 detail。我们还创建了所有字符串项的构造函数。

创建一个 movie_data.dart 文件

import 'package:flutter_shimmer_animation/model/movie_model.dart';

List<MovieModel> allMovies =[

  MovieModel(
      urlImg:'https://gumlet.assettype.com/bloombergquint%2F2019-04%2F4c894d41-181f-4c8c-8630-4604a6d51d05%2Favengers_infinity_war_and_endgame_poster_w7_1600x900.jpg?rect=0%2C0%2C1250%2C900&auto=format%2Ccompress&w=480&dpr=2.6',
      title:'Avengers: Endgame',
      detail:'It s a 2019 American superhero film based '
  ),
  MovieModel(
      urlImg:'https://townsquare.media/site/442/files/2014/08/The-Expendables.jpg?w=980&q=75',
      title:'The Expendables 3',
      detail:'The Expendables 3 is a 2014 American action '
  ),
  MovieModel(
      urlImg:'https://img.etimg.com/thumb/msid-71454408,width-650,imgsize-242226,,resizemode-4,quality-100/war-1.jpg',
      title:'War',
      detail:'War is a 2019 Indian Hindi-language action '
  ),
  MovieModel(
      urlImg:'https://iadsb.tmgrup.com.tr/de9f7e/1200/627/0/0/1000/522?u=https://idsb.tmgrup.com.tr/2019/12/22/1577016105167.jpg',
      title:'Jumanji: The Next Level',
      detail:'Jumanji: The Next Level is a 2019 American '
  ),
  MovieModel(
      urlImg:'https://evertise.net/wp-content/uploads/2021/06/image-366.png',
      title:'Fast & Furious 9',
      detail:'Dom Toretto`s peaceful life off the grid.'
  )

];

在这个 dart 文件中,我们将创建一个电影列表。我们将添加五个MovieModel 的虚拟数据**。**我们添加了 urlImg、title 和 detail 五个不同的数据。

创建一个 custom_widget.dart 文件

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

class CustomWidget extends StatelessWidget {

  final double width;
  final double height;
  final ShapeBorder shapeBorder;

  const CustomWidget.rectangular({
    this.width = double.infinity,
    required this.height
}): this.shapeBorder = const RoundedRectangleBorder();

  const CustomWidget.circular({
    this.width = double.infinity,
    required this.height,
    this.shapeBorder = const CircleBorder()
  });

  @override
  Widget build(BuildContext context)  => Shimmer.fromColors(
    baseColor: Colors.red,
    highlightColor: Colors.grey[300]!,
    period: Duration(seconds: 2),
    child: Container(
      width: width,
      height: height,
      decoration: ShapeDecoration(
        color: Colors.grey[400]!,
        shape: shapeBorder,

      ),
    ),
  );
}

创建一个 my_home_page.dart 文件,创建一个 List电影等于括号和 bool isLoading 等于 false,

List<MovieModel> movies = [];
bool isLoading = false;

@override
void initState() {
  // TODO: implement initState
  super.initState();

  loadData();
}

Future loadData() async {
  setState(() {
    isLoading = true;
  });
  await Future.delayed(Duration(seconds: 2));
  movies = List.of(allMovies);
  setState(() {
    isLoading = false;
  });
}

创建一个buildMovieList()。在这个方法中,我们将添加 ListTile() 小部件。

Widget buildMovieList(MovieModel model) =>
    ListTile(
      leading: CircleAvatar(
        radius: 30,
        backgroundImage: NetworkImage(model.urlImg),
      ),
      title: Text(model.title, style: TextStyle(fontSize: 16),),
      subtitle: Text(
        model.detail, style: TextStyle(fontSize: 14), maxLines: 1,),
    )
  
 Widget buildMovieShimmer() =>
    ListTile(
      leading: CustomWidget.circular(height: 64, width: 64),
      title: Align(
        alignment: Alignment.centerLeft,
        child: CustomWidget.rectangular(height: 16,
          width: MediaQuery.of(context).size.width*0.3,),
      ),
      subtitle: CustomWidget.rectangular(height: 14),
    );

添加ListView.builder()。在里面,添加 itemCount 和 itemBuilder。在 itemBuilder 中,我们将添加条件 if isLoading 然后返回 buildMovieShimmer() 小部件,否则我们将返回最终电影等于电影 [index] 并返回 buildMovieList (movie);

ListView.builder(
    itemCount: isLoading? 5: movies.length,
    itemBuilder: (context, index) {
      if (isLoading) {
        return buildMovieShimmer();
      } else {
        final movie = movies[index];
        return buildMovieList(movie);
      }
    }
),
img

当数据成功加载时,微光停止,所有数据将显示在您的屏幕上。我们还将在 appBar() 上添加一个刷新按钮以获得微光效果。

actions: [
  IconButton(
      icon: Icon(Icons.refresh),
      onPressed: loadData)
],
img

完整代码

import 'package:flutter/material.dart';
import 'package:flutter_shimmer_animation/custom_widget.dart';
import 'package:flutter_shimmer_animation/data/movie_data.dart';
import 'package:flutter_shimmer_animation/model/movie_model.dart';

class MyHomePage extends StatefulWidget {

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage{
  List<MovieModel> movies = [];
  bool isLoading = false;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    loadData();
  }

  Future loadData() async {
    setState(() {
      isLoading = true;
    });
    await Future.delayed(Duration(seconds: 2));
    movies = List.of(allMovies);
    setState(() {
      isLoading = false;
    });
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        backgroundColor: Colors.teal,
        title: Text("Shimmer Animation Effect"),
        actions: [
          IconButton(
              icon: Icon(Icons.refresh),
              onPressed: loadData)
        ],
      ),
      body: ListView.builder(
          itemCount: isLoading? 5: movies.length,
          itemBuilder: (context, index) {
            if (isLoading) {
              return buildMovieShimmer();
            } else {
              final movie = movies[index];
              return buildMovieList(movie);
            }
          }
      ),

    );
  }

  Widget buildMovieList(MovieModel model) =>
      ListTile(
        leading: CircleAvatar(
          radius: 30,
          backgroundImage: NetworkImage(model.urlImg),
        ),
        title: Text(model.title, style: TextStyle(fontSize: 16),),
        subtitle: Text(
          model.detail, style: TextStyle(fontSize: 14), maxLines: 1,),
      );

  Widget buildMovieShimmer() =>
      ListTile(
        leading: CustomWidget.circular(height: 64, width: 64),
        title: Align(
          alignment: Alignment.centerLeft,
          child: CustomWidget.rectangular(height: 16,
            width: MediaQuery.of(context).size.width*0.3,),
        ),
        subtitle: CustomWidget.rectangular(height: 14),
      );

}

原文链接:https://medium.com/flutterdevs/explore-shimmer-animation-effect-in-flutter-7b0e46a9c722


你可能还喜欢

关注「老孟Flutter」
让你每天进步一点点
浏览 213
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报