亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Flutter仿網易怎么實現廣告卡片3D翻轉效果

發布時間:2022-04-27 10:30:08 來源:億速云 閱讀:174 作者:zzz 欄目:開發技術

這篇文章主要介紹“Flutter仿網易怎么實現廣告卡片3D翻轉效果”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Flutter仿網易怎么實現廣告卡片3D翻轉效果”文章能幫助大家解決問題。

    先看下網易新聞的效果:

    Flutter仿網易怎么實現廣告卡片3D翻轉效果

    實現思路

    1、獲取各種距離

    看圖:

    Flutter仿網易怎么實現廣告卡片3D翻轉效果

    思路: 如上圖,狀態欄高度和AppBar的高度我們都可以得到,屏幕的高度我們也可以得到,那么自然我們就可以計算出內容區域的高度,拿到內容區域高度我們先放到一邊,接下來我們需要獲取廣告區域距離AppBar的距離,這是一個進行翻轉核心數據,這里我們可以通過GlobalKey獲取這個組件的渲染對象RenderObject并轉化為RenderBox,通過RenderBox我們可以獲取到這個組件在屏幕上的坐標,這樣我們拿到這個坐標Y軸的值就是當前組件距離頂部的距離

    核心代碼:

    // 這里我們獲取相對于屏幕左上角組件的坐標y軸
    
    GlobalKey _globalKey = GlobalKey();
    
    RenderBox? renderBox =
        _globalKey.currentContext?.findRenderObject() as RenderBox?;
    double? dy = renderBox?.localToGlobal(Offset.zero).dy;

    接下來我們就可以計算出幾個關鍵數據:

    狀態欄高度:stateHeight = MediaQuery.of(context).padding.top;已知。

    AppBar高度:appBarHeight = 56; 默認高度 已知。

    內容區域高度:contentHeight = MediaQuery.of(context).size.height - stateHeight -appBarHeight;

    假設我們廣告區域的高度是200,廣告組件的高度一般都是固定的。

    得出:廣告上方距離頂部的最大距離:maxHeight= contentheight - 200;

    還記得我們上面獲取的dy值嗎,這個值是當前廣告上面距離屏幕頂部的距離,那么我們就可以得出當前廣告距離AppBar底部的距離: bannerY = dy - appBarHeight - stateHeight;

    同理可以得出當前廣告的滑動距離:scrollY = contentheight - 200 - bannerY;

    滑動的最大距離就是:maxSrollY = contentHeight - bannerHeight;

    2、翻轉

    搞定了這些數據,接下來的工作就比較簡單了,我們使用Transform組件來進行180度的翻轉就可以了,
    獲取當前滑動的比例,那就是當前滑動距離/最大滑動距離,也就是 scrollY/maxHeight; 接下來我們看下Transform這個類,

    代碼:

    Container(
        padding: EdgeInsetsDirectional.only(
            start: 20, end: 20, top: 30, bottom: 30),
        height: bannerHeight,
        key: _globalKey,
        child: Transform(
          alignment: Alignment.center, //相對于坐標系原點的對齊方式 從中間翻轉
          transform: Matrix4.identity()//這是一個矩陣變換類,可以對組件的坐標進行翻轉,有興趣可以了解下
            ..rotateX(0)// 翻轉X軸
            ..rotateY(angle),// 翻轉Y軸 這里需要傳入角度
          child: Image.asset(
            "images/img.png",
            fit: BoxFit.fill,
          ),
        ));

    通過rotateY就可以將組件繞著Y軸進行翻轉,也就達到了我們想要的3D效果,上面我們得到了滑動比例,那么我們就可以用這個比例乘以PI值,刷新頁面就可以了唄,接下來我們通過滑動監聽將這個數字進行更新看下效果:

    核心代碼:

    double h = MediaQuery.of(context).size.height; //屏幕高度
    RenderBox? renderBox =
        _globalKey.currentContext?.findRenderObject() as RenderBox?;
    double? dy = renderBox?.localToGlobal(Offset.zero).dy;
    // 56 AppBar 高度
    if (dy != null) {
      // 廣告距離AppBar Y軸距離
      var bannerY = dy - appBarHeight - stateHeight;
      // 主內容區域高度
      var contentHeight = h - appBarHeight - stateHeight;
      if (bannerY + bannerHeight < contentHeight && bannerY > 0) {
        setState(() {
          //滑動的距離
          angle = pi * ((contentHeight - bannerHeight - bannerY) /
                  (contentHeight - bannerHeight));
         
        });
      }
    }

    效果:

    Flutter仿網易怎么實現廣告卡片3D翻轉效果

    翻轉效果確實實現了,不過怎么看著有點不對勁呢,這里有兩個問題:

    1、劃上去翻過來的圖片直接鏡像了。

    Flutter仿網易怎么實現廣告卡片3D翻轉效果

    2、當我們滑動到一半的時候,兩邊的寬度是一致的,3D效果不明顯。

    Flutter仿網易怎么實現廣告卡片3D翻轉效果

    其實這兩個問題都很好解決,

    第一個滑動角度問題,我們滑動到90度進行翻過來的時候只需要將角度+180度進行翻轉即可。這樣就相當于翻了360度,最后自然會回到原來的圖片的樣子。

    第二個我們需要設置Transform的一個屬性..setEntry(3, 2, 0.002),讓卡片翻轉過程中看起來遠小近大的效果。

    我們加上這兩個屬性再看看效果:

    Flutter仿網易怎么實現廣告卡片3D翻轉效果

    這樣看著是不是效果就好多了。

    這里我只簡單了插入了一條廣告,如果有多個廣告建議用一個Map對象將Key存儲起來,因為一個Key只能對應一個組件。

    完整代碼

    class ListViewWidgetDemo extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return ListViewState();
      }
    }
    
    class ListViewState extends State<ListViewWidgetDemo> {
      List<NewsListBean> lis = <NewsListBean>[];
    
      late ScrollController _scrollController = ScrollController();
      String imageUrl =
          "https://images.unsplash.com/photo-1451187580459-43490279c0fa?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60";
    
      GlobalKey _globalKey = GlobalKey();
    
      double angle = 0;
      double bannerHeight = 200;
    
      @override
      void initState() {
        WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
          _scrollController.addListener(() {
            double appBarHeight = 56;
            double stateHeight = MediaQuery.of(context).padding.top;
            double h = MediaQuery.of(context).size.height; //屏幕高度
    
            RenderBox? renderBox =
                _globalKey.currentContext?.findRenderObject() as RenderBox?;
            double? dy = renderBox?.localToGlobal(Offset.zero).dy;
            // 56 AppBar 高度
            if (dy != null) {
              // 廣告距離AppBar Y軸距離
              var bannerY = dy - appBarHeight - stateHeight;
              // 主內容區域高度
              var contentHeight = h - appBarHeight - stateHeight;
              if (bannerY + bannerHeight < contentHeight && bannerY > 0) {
                setState(() {
                  //滑動的距離
                  angle = pi *
                      ((contentHeight - bannerHeight - bannerY) /
                          (contentHeight - bannerHeight));
                  // 前半部分 0-90 后半部分 270-360
                  if (angle >= (pi / 2)) {
                    angle = angle + pi;
                  }
                });
              }
            }
          });
        });
    
        super.initState();
        for (int i = 0; i < 40; i++) {
          lis.add(NewsListBean(
            i.isEven ? 0 : 1,
            "資訊標題$i",
            imageUrl,
          ));
        }
        // 插入廣告
        lis.insert(12, NewsListBean(2, "廣告", imageUrl));
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
              title: Text("仿網易新聞廣告卡片翻轉"),
            ),
            body: ListView.builder(
                controller: _scrollController,
                shrinkWrap: true,
                scrollDirection: Axis.vertical,
                itemCount: lis.length,
                itemBuilder: (context, index) {
                  return _listWidget(lis[index]);
                }));
      }
    
      Widget _listWidget(NewsListBean bean) {
        late Widget widget;
        switch (bean.type) {
          case 0:
            widget = Container(
                height: 50,
                padding: EdgeInsetsDirectional.only(start: 20),
                alignment: Alignment.centerLeft,
                color: Colors.blue[200],
                child: Text(
                  bean.title,
                  style: TextStyle(),
                ));
            break;
          case 1:
            widget = Row(
              children: [
                Expanded(
                  child: Container(
                      height: 80,
                      alignment: Alignment.center,
                      color: Colors.red[200],
                      margin: EdgeInsets.all(10),
                      child: Text(bean.title)),
                ),
                Image.network(
                  bean.image,
                  width: 40,
                  height: 40,
                )
              ],
            );
            break;
          case 2:
            widget = Container(
                padding: EdgeInsetsDirectional.only(
                    start: 20, end: 20, top: 30, bottom: 30),
                height: bannerHeight,
                key: _globalKey,
                child: Transform(
                  alignment: Alignment.center, //相對于坐標系原點的對齊方式
                  transform: Matrix4.identity()
                    ..setEntry(3, 2, 0.002)
                    ..rotateX(0)
                    ..rotateY(angle),
                  child: Image.asset(
                    "images/img.png",
                    fit: BoxFit.fill,
                  ),
                ));
            break;
          default:
            widget = SizedBox();
            break;
        }
        return widget;
      }
    }
    class NewsListBean {
      //資訊類型 0:資訊無圖 1:資訊有圖 2:3d廣告
      final int type;
      final bool isFirst;
      final String title;
      final String image;
    
      NewsListBean(this.type, this.title, this.image, {this.isFirst = false});
    }

    關于“Flutter仿網易怎么實現廣告卡片3D翻轉效果”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    牙克石市| 太原市| 全州县| 晴隆县| 绥中县| 驻马店市| 张掖市| 江口县| 舒城县| 泾源县| 交城县| 根河市| 那曲县| 景宁| 玉门市| 栾城县| 株洲县| 光山县| 乡宁县| 峨眉山市| 陆丰市| 手机| 南溪县| 固始县| 焦作市| 霍邱县| 清原| 清徐县| 三原县| 文化| 衡东县| 古田县| 满洲里市| 木里| 靖宇县| 高碑店市| 遂宁市| 宣武区| 含山县| 苍山县| 深水埗区|