一步一步完成Flutter應用開發-掘金App文章詳情, 懸浮,標題動畫

一天清晨 發表於 2021-03-24

這邊文章主要將掘金app的文章詳情介面的內容構造和效果的實現,也是完結篇,或者有興趣的同學們可以談論想要去實現哪個頁面的或者功能都可以談論起來。一起進步。一個人終究沒有一群人會走得遠。

標題部分

看了一下掘金app文章詳情的效果,我的思路是自定義一個appbar然後,左半部分是一個返回按鈕,右部分是點選彈出分享的懸浮視窗,中間部分根據內容列表的滑動進行改變,大體思路就是通過pageView構建中間部分,禁止手勢滑動,使用主動觸發滑動效果,觸發機制是內容滑動改變的距離 效果如下:

tutieshi_640x1343_4s.gif

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class DetailPage extends StatefulWidget {
  DetailPage({Key key}) : super(key: key);

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

class _DetailPageState extends State<DetailPage> {
  PageController controller = new PageController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
      children: [
        Container(
          width: Get.width,
          height: 80,
          decoration: BoxDecoration(color: Colors.white),
          padding: EdgeInsets.only(
              top: Get.context.mediaQueryPadding.top, left: 10, right: 10),
          child: Row(
            children: [
              InkWell(
                child: Icon(
                  CupertinoIcons.back,
                  color: Color.fromRGBO(38, 38, 40, 1),
                ),
                onTap: () {
                  print('點選了返回');
                  Get.back();
                },
              ),
              Expanded(
                  child: PageView.builder(
                itemBuilder: (context, index) {
                  if (index == 0) {
                    return Container(
                      alignment: Alignment.center,
                      child: Text('一步一步完成Flutter應用開發-掘金文章詳情頁面'),
                    );
                  }
                  return Container(
                    child: Row(
                      children: [
                        Container(
                          height: 20,
                          width: 20,
                          decoration: BoxDecoration(
                              color: Colors.red,
                              borderRadius: BorderRadius.circular(10)),
                        )
                      ],
                    ),
                  );
                },
                itemCount: 2,
                scrollDirection: Axis.vertical,
                physics: NeverScrollableScrollPhysics(),
                controller: controller,
              )),
              InkWell(
                child: Icon(
                  Icons.list,
                  color: Color.fromRGBO(38, 38, 40, 1),
                ),
                onTap: () {
                  controller.animateTo(40,
                      duration: Duration(milliseconds: 500),
                      curve: Curves.ease);
                },
              ),
            ],
          ),
        )
      ],
    ));
  }
}
複製程式碼

基於這個思想接下來完成下面的內容

內容部分的構建

這部分想要知道掘金內容的返回格式是什麼,是markdown內容或者是html內容,如果是html內容傳送門,可以參考一下。 效果:

tutieshi_640x1343_5s.gif 這塊主要是通過markdown形式展示詳情內容引入

flutter_markdown: ^0.5.2
複製程式碼

在上述程式碼中加入詳情內容程式碼

ScrollController _scrollController = new ScrollController();

  @override
  void initState() {
    super.initState();
    _scrollController
      ..addListener(() {
        setState(() {
          if (_scrollController.offset > 88 && _scrollController.offset < 100) {
            controller.animateTo(30,
                duration: Duration(milliseconds: 500), curve: Curves.ease);
          } else if (_scrollController.offset <= 0) {
            controller.animateTo(0,
                duration: Duration(milliseconds: 500), curve: Curves.ease);
          }
        });
      });
  }
  
  @override
  Widget build(BuildContext context) {
      ...省略上述程式碼
      //_markdownData為內容常量
      Expanded(
            child: Markdown(
          data: _markdownData,
          controller: _scrollController,
        ))
  }
 
複製程式碼

懸浮彈窗

使用getX的Get.dialog進行展示懸浮彈窗 效果:

tutieshi_640x1343_4s.gif

程式碼如下:

renderItem(title) {
    return Column(
      children: [
        Container(
          height: 40,
          width: 40,
          margin: EdgeInsets.only(top: 10),
          decoration: BoxDecoration(
              color: Colors.red, borderRadius: BorderRadius.circular(20)),
        ),
        Padding(padding: EdgeInsets.only(top: 8)),
        Material(
          child: Text(title),
        )
      ],
    );
  }

//呼叫方法
Get.dialog(
                      UnconstrainedBox(
                        alignment: Alignment.bottomCenter,
                        child: Container(
                            width: Get.width,
                            height: Get.height * 0.6,
                            decoration: BoxDecoration(
                                color: Colors.white,
                                borderRadius: BorderRadius.only(
                                    topLeft: Radius.circular(20),
                                    topRight: Radius.circular(20))),
                            child: Column(
                              children: [
                                Padding(padding: EdgeInsets.only(top: 40)),
                                Row(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceAround,
                                  crossAxisAlignment: CrossAxisAlignment.center,
                                  children: [
                                    renderItem('卡片分享'),
                                    renderItem('微信分享'),
                                    renderItem('朋友圈分享'),
                                    renderItem('微博分享'),
                                  ],
                                ),
                                Padding(padding: EdgeInsets.only(top: 20)),
                                Divider(
                                  height: 2,
                                  color: Colors.grey,
                                ),
                                Padding(padding: EdgeInsets.only(top: 20)),
                                Row(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceAround,
                                  crossAxisAlignment: CrossAxisAlignment.center,
                                  children: [
                                    renderItem('卡片分享'),
                                    renderItem('微信分享'),
                                    renderItem('朋友圈分享'),
                                    renderItem('微博分享'),
                                  ],
                                ),
                                Row(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceAround,
                                  crossAxisAlignment: CrossAxisAlignment.center,
                                  children: [
                                    renderItem('卡片分享'),
                                    renderItem('微信分享'),
                                    renderItem('朋友圈分享'),
                                    renderItem('微信分享'),
                                  ],
                                ),
                                Expanded(child: Container()),
                                GestureDetector(
                                  onTap: () {
                                    Get.back();
                                  },
                                  child: Container(
                                    margin: EdgeInsets.only(
                                        bottom: Get
                                            .context.mediaQueryPadding.bottom),
                                    width: Get.width,
                                    height: 40,
                                    alignment: Alignment.center,
                                    child: Material(
                                      child: Text(
                                        '取消',
                                      ),
                                    ),
                                  ),
                                ),
                              ],
                            )),
                      ),
                      useRootNavigator: false,
                      useSafeArea: false);
複製程式碼

over ~~~~