Flutter占位符与加载状态插件skeletonsplus的使用

发布于 1周前 作者 vueper 来自 Flutter

Flutter占位符与加载状态插件skeletonsplus的使用

Skeletonsplus

Skeletonsplus 是一个用于在加载数据时为 Flutter 应用程序构建自定义骨架小部件的包。

skeletons 包 fork 并迁移以支持 Flutter 3.22。

示例

列表视图(默认)

Items Paragraphs ListView (默认)
items paragraphs listview_default

列表视图(自定义)和复杂卡片

ListView (自定义) ListView (复杂卡片) SkeletonTheme
listview_custom listview_cards skeleton_theme

明暗模式和右到左布局

明暗模式 右到左 自定义闪光效果
light_dark_modes rtl custom_shimmer

所有示例可以在 这里 查看。

如何使用

可以通过将子部件封装在一个 Skeleton 小部件中来使用它:

import 'package:skeletonsplus/skeletonsplus.dart';

Skeleton(
  isLoading: _isLoading,
  skeleton: SkeletonListView(),
  child: Container(child: Center(child: Text("Content"))),
)

或者直接使用:

Container(
  child: _isLoading 
    ? SkeletonListView() 
    : Container(child: Center(child: Text("Content"))),
)

还可以使用 SkeletonTheme 来设置所有后代骨架小部件的默认配置:

SkeletonTheme(
  shimmerGradient: LinearGradient(
    colors: [
      Color(0xFFD8E3E7),
      Color(0xFFC8D5DA),
      Color(0xFFD8E3E7),
    ],
    stops: [
      0.1,
      0.5,
      0.9,
    ],
  ),
  darkShimmerGradient: LinearGradient(
    colors: [
      Color(0xFF222222),
      Color(0xFF242424),
      Color(0xFF2B2B2B),
      Color(0xFF242424),
      Color(0xFF222222),
    ],
    stops: [
      0.0,
      0.2,
      0.5,
      0.8,
      1,
    ],
    begin: Alignment(-2.4, -0.2),
    end: Alignment(2.4, 0.2),
    tileMode: TileMode.clamp,
  ),
  child: MaterialApp(
    ...
  ),
)

更多定制

对于更复杂的形状,可以使用 SkeletonItem 小部件来构建你的骨架:

ListView.builder(
  physics: NeverScrollableScrollPhysics(),
  itemCount: 5,
  itemBuilder: (context, index) => Padding(
    padding: const EdgeInsets.all(8.0),
    child: Container(
      padding: const EdgeInsets.all(8.0),
      decoration: BoxDecoration(color: Colors.white),
      child: SkeletonItem(
        child: Column(
          children: [
            Row(
              children: [
                SkeletonAvatar(
                  style: SkeletonAvatarStyle(
                    shape: BoxShape.circle,
                    width: 50,
                    height: 50,
                  ),
                ),
                SizedBox(width: 8),
                Expanded(
                  child: SkeletonParagraph(
                    style: SkeletonParagraphStyle(
                      lines: 3,
                      spacing: 6,
                      lineStyle: SkeletonLineStyle(
                        randomLength: true,
                        height: 10,
                        borderRadius: BorderRadius.circular(8),
                        minLength: MediaQuery.of(context).size.width / 6,
                        maxLength: MediaQuery.of(context).size.width / 3,
                      ),
                    ),
                  ),
                )
              ],
            ),
            SizedBox(height: 12),
            SkeletonParagraph(
              style: SkeletonParagraphStyle(
                lines: 3,
                spacing: 6,
                lineStyle: SkeletonLineStyle(
                  randomLength: true,
                  height: 10,
                  borderRadius: BorderRadius.circular(8),
                  minLength: MediaQuery.of(context).size.width / 2,
                ),
              ),
            ),
            SizedBox(height: 12),
            SkeletonAvatar(
              style: SkeletonAvatarStyle(
                width: double.infinity,
                minHeight: MediaQuery.of(context).size.height / 8,
                maxHeight: MediaQuery.of(context).size.height / 3,
              ),
            ),
            SizedBox(height: 8),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Row(
                  children: [
                    SkeletonAvatar(style: SkeletonAvatarStyle(width: 20, height: 20)),
                    SizedBox(width: 8),
                    SkeletonAvatar(style: SkeletonAvatarStyle(width: 20, height: 20)),
                    SizedBox(width: 8),
                    SkeletonAvatar(style: SkeletonAvatarStyle(width: 20, height: 20)),
                  ],
                ),
                SkeletonLine(
                  style: SkeletonLineStyle(
                    height: 16,
                    width: 64,
                    borderRadius: BorderRadius.circular(8),
                  ),
                )
              ],
            )
          ],
        ),
      ),
    ),
  ),
);

更多关于Flutter占位符与加载状态插件skeletonsplus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter占位符与加载状态插件skeletonsplus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用skeletons_plus插件来展示占位符和加载状态的示例代码。skeletons_plus是一个强大的库,可以帮助你在数据加载时显示占位符,从而提高用户体验。

首先,你需要在你的pubspec.yaml文件中添加skeletons_plus依赖:

dependencies:
  flutter:
    sdk: flutter
  skeletons_plus: ^2.0.0  # 请检查最新版本号

然后,运行flutter pub get来安装依赖。

接下来,是一个简单的Flutter应用示例,展示如何使用skeletons_plus来显示占位符和加载状态:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Skeletons+ Example'),
        ),
        body: Center(
          child: MySkeletonScreen(),
        ),
      ),
    );
  }
}

class MySkeletonScreen extends StatefulWidget {
  @override
  _MySkeletonScreenState createState() => _MySkeletonScreenState();
}

class _MySkeletonScreenState extends State<MySkeletonScreen> with SingleTickerProviderStateMixin {
  bool isLoading = true; // 模拟数据加载状态

  @override
  void initState() {
    super.initState();
    // 模拟数据加载过程
    Future.delayed(Duration(seconds: 2), () {
      setState(() {
        isLoading = false;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return isLoading
        ? SkeletonScreen(
            skeleton: Column(
              children: [
                SkeletonAnimatedLine(width: double.infinity, height: 50), // 模拟标题
                SizedBox(height: 10),
                SkeletonAnimatedLine(width: double.infinity, height: 150), // 模拟图片或内容区域
                SizedBox(height: 10),
                SkeletonAnimatedLine(width: double.infinity, height: 40), // 模拟描述或按钮
              ],
            ),
            duration: 1000, // 动画持续时间
          )
        : Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'Title',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
              SizedBox(height: 10),
              Image.network(
                'https://via.placeholder.com/150',
                width: double.infinity,
                height: 150,
                fit: BoxFit.cover,
              ),
              SizedBox(height: 10),
              Text(
                'This is a description or a button area.',
                style: TextStyle(fontSize: 16),
              ),
            ]);
  }
}

在这个示例中:

  1. MyApp是一个简单的Flutter应用,它包含一个Scaffold,其中包含一个标题和一个中心对齐的MySkeletonScreen
  2. MySkeletonScreen是一个状态组件,用于模拟数据加载状态。
  3. initState方法中,我们使用Future.delayed来模拟一个异步数据加载过程,2秒后设置isLoadingfalse
  4. build方法根据isLoading的值返回不同的Widget:
    • 如果isLoadingtrue,则显示一个SkeletonScreen,其中包含几个SkeletonAnimatedLine来模拟加载中的UI元素。
    • 如果isLoadingfalse,则显示实际的UI元素,如标题、图片和描述文本。

这样,你就可以在你的Flutter应用中使用skeletons_plus来优雅地显示占位符和加载状态了。

回到顶部