使用CustomScrollView+SliverAppBar+Animation实现

1.展示界面

import 'package:flutter/material.dart';
import 'package:testflutte/mainviews/SliverAppBar.dart';
class MySliverView extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _MySliverView();
  }

}

class _MySliverView extends State<MySliverView>with TickerProviderStateMixin {

  double extraPicHeight = 0.0;//初始化要加载到图片上的高度
  BoxFit fitType;//图片填充类型(刚开始滑动时是以宽度填充,拉开之后以高度填充)
  double prev_dy;//前一次手指所在处的y值
  AnimationController animationController;
  Animation<double> anim;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    animationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 300));
    anim = Tween(begin: 0.0, end: 0.0).animate(animationController);
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    animationController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
        body: Listener(
          onPointerMove: (result) {//手指的移动时
            updatePicHeight(result.position.dy);//自定义方法,图片的放大由它完成。
          },
          onPointerUp: (_) {//当手指抬起离开屏幕时
            runAnimate();//动画执行
            animationController.forward(from: 0.0);//重置动画
          },
          child: CustomScrollView(
            slivers: <Widget>[
              SliverAppBar(
                leading: IconButton(//标题左侧的控件(一般是返回上一个页面的箭头)
                  icon: Icon(Icons.arrow_back),
                  onPressed: () {
                    Navigator.pop(context);
                  },
                ),
                floating: false,
                pinned: true,
                snap: false,
                //pinned代表是否会在顶部保留AppBar
                //floating代表是否会发生下拉立即出现SliverAppBar
                //snap必须与floating:true联合使用,表示显示SliverAppBar之后,如果没有完全拉伸,是否会完全神展开
                expandedHeight: 236 + extraPicHeight,//顶部控件所占的高度,跟随因手指滑动所产生的位置变化而变化。
                flexibleSpace: FlexibleSpaceBar(
                    title: null,//标题
                    background://背景图片所在的位置
                    SliverAppBar(extraPicHeight: extraPicHeight,
                      fitType: fitType,)//自定义Widget
                ),
              ),
              SliverList(//列表
                  delegate: SliverChildBuilderDelegate((context,i){
                    return Container(
                      padding: EdgeInsets.all(16.0),
                      child: Text("This is item $i",
                        style: TextStyle(fontSize: 20.0),),
                      color: Colors.white70,);
                  },))
            ],
          ),
        )
    );

  }

  updatePicHeight(changed){
    if(prev_dy == 0.0){//如果是手指第一次点下时,图片大小不直接变化,所以进行一个判定。
      prev_dy = changed;
    }
    if(extraPicHeight >= 45.0){//当我们加载到图片上的高度大于某个值的时候,改变图片的填充方式,让它由以宽度填充变为以高度填充,从而实现了图片视角上的放大。
      fitType = BoxFit.fitHeight;
    }
    else{
      fitType = BoxFit.fitWidth;
    }
    extraPicHeight += changed - prev_dy;//新的一个y值减去前一次的y值然后累加,作为加载到图片上的高度。
    setState(() {//更新数据
      prev_dy = changed;
      extraPicHeight = extraPicHeight;
      fitType = fitType;
    });
  }

  runAnimate(){//设置动画让extraPicHeight的值从当前的值渐渐回到 0
    setState(() {
      anim = Tween(begin: extraPicHeight, end: 0.0).animate(animationController)
        ..addListener((){
          if(extraPicHeight>=45.0){//同样改变图片填充类型
            fitType = BoxFit.fitHeight;
          }
          else{
            fitType = BoxFit.fitWidth;
          }
          setState(() {
            extraPicHeight = anim.value;
            fitType = fitType;
          });
        });
      prev_dy = 0.0;//同样归零
    });
  }
}

2.绘制的appbar

import 'package:flutter/material.dart';

class SliverAppBar extends StatelessWidget{
  const SliverAppBar ({Key key, @required this.extraPicHeight, @required this.fitType}) : super(key: key);
  final double extraPicHeight;//传入图片加载的高度
  final BoxFit fitType;//传入的填充方式

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Stack(
      children: <Widget>[
        Column(
          children: <Widget>[
            Container(//缩放的图片
              width: MediaQuery.of(context).size.width,
              child: Image.asset("assets/image/f_image.webp",
                  height: 180 + extraPicHeight,fit: fitType),
            ),
            Container(
              height: 80.0,
              width: MediaQuery.of(context).size.width,
              color: Colors.white,
              child: Column(
                children: <Widget>[
                  Container(
                    padding: EdgeInsets.only(left: 16.0,top: 10.0),
                    child: Text("QQ:777777777"),
                  ),
                  Container(
                    padding: EdgeInsets.only(left: 16.0,top: 8.0),
                    child: Text("女:日本人"),
                  )
                ],
              ),
            ),
          ],
        ),
        Positioned(
          left: 30.0,
          top: 130.0 + extraPicHeight,
          child: Container(
            width: 100.0,
            height: 100.0,
            child: CircleAvatar(
              backgroundImage: AssetImage('assets/image/f_image.webp'),
            ),
          ),

        )
      ],

    );
  }

}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐