最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android Flutter自適應(yīng)瀑布流案例詳解

 更新時(shí)間:2021年09月13日 08:51:01   作者:阿 T  
這篇文章主要介紹了Android Flutter自適應(yīng)瀑布流案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

Flutter自適應(yīng)瀑布流

前言:在電商app經(jīng)常會(huì)看到首頁商品推薦的瀑布流,或者類似短視頻app首頁也是瀑布流,這些都是需要自適應(yīng)的,才能給用戶帶來好的體驗(yàn)

話不多說先上效果圖:

在這里插入圖片描述

在這里插入圖片描述

根據(jù)效果圖可以分為四步:

  1. 圖片自適應(yīng)
  2. 自適應(yīng)標(biāo)簽
  3. 上拉刷新和下拉加載
  4. 底部的點(diǎn)贊按鈕可以去掉或者自己修改樣式,我這里使用的like_button庫

注:本文使用的庫:為啥這么多呢,因?yàn)槲野褕D片緩存這樣?xùn)|西都加上了,單純的瀑布流就用waterfall_flow

waterfall_flow: ^3.0.1
extended_image: any
extended_sliver: any
ff_annotation_route_library: any
http_client_helper: any
intl: any
like_button: any
loading_more_list: any
pull_to_refresh_notification: any
url_launcher: any

1.圖片自適應(yīng):

Widget image = Stack(
  children: <Widget>[
    ExtendedImage.network(
      item.imageUrl,
      shape: BoxShape.rectangle,
      //clearMemoryCacheWhenDispose: true,
      border: Border.all(color: Colors.grey.withOpacity(0.4), width: 1.0),
      borderRadius: const BorderRadius.all(
        Radius.circular(10.0),
      ),
      loadStateChanged: (ExtendedImageState value) {
        if (value.extendedImageLoadState == LoadState.loading) {
          Widget loadingWidget = Container(
            alignment: Alignment.center,
            color: Colors.grey.withOpacity(0.8),
            child: CircularProgressIndicator(
              strokeWidth: 2.0,
              valueColor:
                  AlwaysStoppedAnimation<Color>(Theme.of(c).primaryColor),
            ),
          );
          if (!konwSized) {
            //todo: not work in web
            loadingWidget = AspectRatio(
              aspectRatio: 1.0,
              child: loadingWidget,
            );
          }
          return loadingWidget;
        } else if (value.extendedImageLoadState == LoadState.completed) {
          item.imageRawSize = Size(
              value.extendedImageInfo.image.width.toDouble(),
              value.extendedImageInfo.image.height.toDouble());
        }
        return null;
      },
    ),
    Positioned(
      top: 5.0,
      right: 5.0,
      child: Container(
        padding: const EdgeInsets.all(3.0),
        decoration: BoxDecoration(
          color: Colors.grey.withOpacity(0.6),
          border: Border.all(color: Colors.grey.withOpacity(0.4), width: 1.0),
          borderRadius: const BorderRadius.all(
            Radius.circular(5.0),
          ),
        ),
        child: Text(
          '${index + 1}',
          textAlign: TextAlign.center,
          style: const TextStyle(fontSize: fontSize, color: Colors.white),
        ),
      ),
    )
  ],
);
if (konwSized) {
    image = AspectRatio(
      aspectRatio: item.imageSize.width / item.imageSize.height,
      child: image,
    );
  } else if (item.imageRawSize != null) {
    image = AspectRatio(
      aspectRatio: item.imageRawSize.width / item.imageRawSize.height,
      child: image,
    );
  }
 return Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      image,
      const SizedBox(
        height: 5.0,
      ),
      buildTagsWidget(item),
      const SizedBox(
        height: 5.0,
      ),
      buildBottomWidget(item),
    ],
  );
}

2.自適應(yīng)標(biāo)簽:

Widget buildTagsWidget(
  TuChongItem item, {
  int maxNum = 6,
}) {
  const double fontSize = 12.0;
  return Wrap(
      runSpacing: 5.0,
      spacing: 5.0,
      children: item.tags.take(maxNum).map<Widget>((String tag) {
        final Color color = item.tagColors[item.tags.indexOf(tag)];
        return Container(
          padding: const EdgeInsets.all(3.0),
          decoration: BoxDecoration(
            color: color,
            border: Border.all(color: Colors.grey.withOpacity(0.4), width: 1.0),
            borderRadius: const BorderRadius.all(
              Radius.circular(5.0),
            ),
          ),
          child: Text(
            tag,
            textAlign: TextAlign.start,
            style: TextStyle(
                fontSize: fontSize,
                color: color.computeLuminance() < 0.5
                    ? Colors.white
                    : Colors.black),
          ),
        );
      }).toList());
}

3.上拉刷新和下拉加載

class PullToRefreshHeader extends StatelessWidget {
  const PullToRefreshHeader(this.info, this.lastRefreshTime, {this.color});
  final PullToRefreshScrollNotificationInfo info;
  final DateTime lastRefreshTime;
  final Color color;
  @override
  Widget build(BuildContext context) {
    if (info == null) {
      return Container();
    }
    String text = '';
    if (info.mode == RefreshIndicatorMode.armed) {
      text = 'Release to refresh';
    } else if (info.mode == RefreshIndicatorMode.refresh ||
        info.mode == RefreshIndicatorMode.snap) {
      text = 'Loading...';
    } else if (info.mode == RefreshIndicatorMode.done) {
      text = 'Refresh completed.';
    } else if (info.mode == RefreshIndicatorMode.drag) {
      text = 'Pull to refresh';
    } else if (info.mode == RefreshIndicatorMode.canceled) {
      text = 'Cancel refresh';
    }

    final TextStyle ts = const TextStyle(
      color: Colors.grey,
    ).copyWith(fontSize: 13);

    final double dragOffset = info?.dragOffset ?? 0.0;

    final DateTime time = lastRefreshTime ?? DateTime.now();
    final double top = -hideHeight + dragOffset;
    return Container(
      height: dragOffset,
      color: color ?? Colors.transparent,
      //padding: EdgeInsets.only(top: dragOffset / 3),
      //padding: EdgeInsets.only(bottom: 5.0),
      child: Stack(
        children: <Widget>[
          Positioned(
            left: 0.0,
            right: 0.0,
            top: top,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Expanded(
                  child: Container(
                    alignment: Alignment.centerRight,
                    child: RefreshImage(top),
                    margin: const EdgeInsets.only(right: 12.0),
                  ),
                ),
                Column(
                  children: <Widget>[
                    Text(
                      text,
                      style: ts,
                    ),
                    Text(
                      'Last updated:' +
                          DateFormat('yyyy-MM-dd hh:mm').format(time),
                      style: ts.copyWith(fontSize: 12),
                    )
                  ],
                ),
                Expanded(
                  child: Container(),
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

class RefreshImage extends StatelessWidget {
  const RefreshImage(this.top);
  final double top;
  @override
  Widget build(BuildContext context) {
    const double imageSize = 40;
    return ExtendedImage.asset(
      Assets.assets_fluttercandies_grey_png,
      width: imageSize,
      height: imageSize,
      afterPaintImage: (Canvas canvas, Rect rect, ui.Image image, Paint paint) {
        final double imageHeight = image.height.toDouble();
        final double imageWidth = image.width.toDouble();
        final Size size = rect.size;
        final double y = (1 - min(top / (refreshHeight - hideHeight), 1)) *
            imageHeight;

        canvas.drawImageRect(
            image,
            Rect.fromLTWH(0.0, y, imageWidth, imageHeight - y),
            Rect.fromLTWH(rect.left, rect.top + y / imageHeight * size.height,
                size.width, (imageHeight - y) / imageHeight * size.height),
            Paint()
              ..colorFilter =
                  const ColorFilter.mode(Color(0xFFea5504), BlendMode.srcIn)
              ..isAntiAlias = false
              ..filterQuality = FilterQuality.low);

        //canvas.restore();
      },
    );
  }
}

4.底部的點(diǎn)贊按鈕

LikeButton(
  size: 18.0,
  isLiked: item.isFavorite,
  likeCount: item.favorites,
  countBuilder: (int count, bool isLiked, String text) {
    final ColorSwatch<int> color =
        isLiked ? Colors.pinkAccent : Colors.grey;
    Widget result;
    if (count == 0) {
      result = Text(
        'love',
        style: TextStyle(color: color, fontSize: fontSize),
      );
    } else {
      result = Text(
        count >= 1000 ? (count / 1000.0).toStringAsFixed(1) + 'k' : text,
        style: TextStyle(color: color, fontSize: fontSize),
      );
    }
    return result;
  },
  likeCountAnimationType: item.favorites < 1000
      ? LikeCountAnimationType.part
      : LikeCountAnimationType.none,
  onTap: (bool isLiked) {
    return onLikeButtonTap(isLiked, item);
  },
)

這樣自適應(yīng)的瀑布流就完成了。

到此這篇關(guān)于Android Flutter自適應(yīng)瀑布流案例詳解的文章就介紹到這了,更多相關(guān)Android Flutter自適應(yīng)瀑布流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android 推送原理(Android Push Notification)詳解

    Android 推送原理(Android Push Notification)詳解

    這篇文章主要介紹了Android 推送原理(Android Push Notification)詳解的相關(guān)資料,這里對(duì)Android 推送的原理做了簡(jiǎn)單的介紹,需要的朋友可以參考下
    2016-11-11
  • Android內(nèi)存泄漏導(dǎo)致原因深入探究

    Android內(nèi)存泄漏導(dǎo)致原因深入探究

    內(nèi)存管理的目的就是讓我們?cè)陂_發(fā)過程中有效避免我們的應(yīng)用程序出現(xiàn)內(nèi)存泄露的問題。內(nèi)存泄露相信大家都不陌生,我們可以這樣理解:沒有用的對(duì)象無法回收的現(xiàn)象就是內(nèi)存泄露
    2023-02-02
  • Android RxJava異步數(shù)據(jù)處理庫使用詳解

    Android RxJava異步數(shù)據(jù)處理庫使用詳解

    RxJava是一種異步數(shù)據(jù)處理庫,也是一種擴(kuò)展的觀察者模式。對(duì)于Android開發(fā)者來說,使用RxJava時(shí)也會(huì)搭配RxAndroid,它是RxJava針對(duì)Android平臺(tái)的一個(gè)擴(kuò)展,用于Android 開發(fā),它提供了響應(yīng)式擴(kuò)展組件,使用RxAndroid的調(diào)度器可以解決Android多線程問題
    2022-11-11
  • Android如何讀寫CSV文件方法示例

    Android如何讀寫CSV文件方法示例

    CSV 文件是Excel 的標(biāo)準(zhǔn)文件格式,在開發(fā)過程中經(jīng)常需要格式化輸出數(shù)據(jù)。CSV 的格式非常簡(jiǎn)單,都是一行一行存儲(chǔ)的,同一行不同列之間用逗號(hào)隔開。下面這篇文章主要給大家介紹了關(guān)于Android如何讀寫CSV文件的相關(guān)資料,需要的朋友可以參考下。
    2017-08-08
  • Android app啟動(dòng)時(shí)黑屏或者白屏的原因及解決辦法

    Android app啟動(dòng)時(shí)黑屏或者白屏的原因及解決辦法

    這篇文章主要介紹了Android app啟動(dòng)時(shí)黑屏或者白屏的原因及解決辦法的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • Android本地搜索業(yè)務(wù)優(yōu)化方案

    Android本地搜索業(yè)務(wù)優(yōu)化方案

    這篇文章主要為大家介紹了Android本地搜索業(yè)務(wù)優(yōu)化方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Android DrawerLayout實(shí)現(xiàn)抽屜效果實(shí)例代碼

    Android DrawerLayout實(shí)現(xiàn)抽屜效果實(shí)例代碼

    這篇文章主要介紹了Android DrawerLayout實(shí)現(xiàn)抽屜效果的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-12-12
  • Android 系統(tǒng)服務(wù)TelecomService啟動(dòng)過程原理分析

    Android 系統(tǒng)服務(wù)TelecomService啟動(dòng)過程原理分析

    這篇文章主要介紹了Android 系統(tǒng)服務(wù)TelecomService啟動(dòng)過程原理分析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Android ListView之setEmptyView正確使用方法

    Android ListView之setEmptyView正確使用方法

    這篇文章主要介紹了Android ListView之setEmptyView正確使用方法的相關(guān)資料,希望通過本文能幫助到大家使用該方法,需要的朋友可以參考下
    2017-09-09
  • Android Rreact Native 常見錯(cuò)誤總結(jié)

    Android Rreact Native 常見錯(cuò)誤總結(jié)

    這篇文章主要介紹了Android Rreact Native 常見錯(cuò)誤總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06

最新評(píng)論

江安县| 彰化市| 横峰县| 四会市| 贵阳市| 镇康县| 堆龙德庆县| 黄冈市| 汽车| 电白县| 彩票| 龙江县| 西丰县| 开阳县| 黄梅县| 疏附县| 夏河县| 轮台县| 嵊州市| 建平县| 郁南县| 北安市| 兰西县| 河北区| 平乐县| 东兰县| 五台县| 铜山县| 广元市| 萍乡市| 开封县| 南京市| 凤阳县| 买车| 和田市| 茂名市| 阜新市| 县级市| 宜章县| 兴隆县| 大新县|