追梦App开发记录

追梦App是我们实验室一个大佬发起的,详情见https://blog.csdn.net/qq_46101869/category_10342068.html

然后我按着设计图用flutter去实现前端,设计图是这样的↓,这是追梦App的引导部分

在这里插入图片描述

一开始我看到显示翻页的小圆点想用的是swiper,可是这里又是点击下一步的按钮才翻页,知识盲区,百度了很久只找到修改pagination的。于是后来打算老老实实做三个页面,小圆点是画的。

这个背景很好康,但是我在实现的时候有些复杂,用了两次贝塞尔曲线,用不同透明度的颜色叠加。

class background extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        ClipPath(
          clipper: MyClipper(),
          child: Container(
              height: 400,
              color: Theme.of(context).primaryColor.withOpacity(0.05),
              child: ClipPath(
                clipper: MyClipper2(),
                child: Container(
                    height:400,
                    width: double.infinity,
                    color: Theme.of(context).primaryColor.withOpacity(0.06),
                ),
              )
          ),
        )
      ],
    );
  }
}

class MyClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    var path = new Path();
    path.lineTo(0, size.height - 100);
    var controllPoint = Offset(50, size.height);
    var endPoint = Offset(size.width/2+50, size.height);
    path.quadraticBezierTo(controllPoint.dx, controllPoint.dy, endPoint.dx, endPoint.dy);
    controllPoint=Offset(size.width-80,size.height);
    endPoint=Offset(size.width,size.height-50);
    path.quadraticBezierTo(controllPoint.dx, controllPoint.dy, endPoint.dx, endPoint.dy);
    path.lineTo(size.width, size.height);
    path.lineTo(size.width, 0);
    return path;
  }
  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true;
  }
}

class MyClipper2 extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    var path = new Path();
    path.lineTo(0, size.height - 110);
    var controllPoint = Offset(50, size.height-20);
    var endPoint = Offset(size.width/2, size.height-20);
    path.quadraticBezierTo(controllPoint.dx, controllPoint.dy, endPoint.dx, endPoint.dy);
    controllPoint=Offset(size.width-100,size.height-20);
    endPoint=Offset(size.width,size.height-80);
    path.quadraticBezierTo(controllPoint.dx, controllPoint.dy, endPoint.dx, endPoint.dy);
    path.lineTo(size.width, size.height);
    path.lineTo(size.width, 0);
    return path;
  }
  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true;
  }
}

按顺序实现,p1中白底的的文本框要求能够输入文字,所以用了textField

class TextFieldDemo extends StatefulWidget {
  @override
  _TextFieldDemoState createState() => _TextFieldDemoState();
}

class _TextFieldDemoState extends State<TextFieldDemo> {
  final textEditingController = TextEditingController();

  @override
  void dispose() {
    textEditingController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return TextField(
      textAlign: TextAlign.center,
      controller: textEditingController,
      onSubmitted: (value){
        debugPrint('submit: $value');
      },
      decoration: InputDecoration(
        hintText: '在此输入你的目标描述',
        border: InputBorder.none,//input没有下划线了
        fillColor: Colors.white,
        filled: true,
      ),
      style: TextStyle(
          color: Theme.of(context).primaryColor,
          fontSize: 15
      ),
    );
  }
}

接下来就是一段导语 和 模拟的分页指示器

//导语
            Container(
              width:270,
              child: Text('你的目标将会是你之后道路上一直要追寻的梦想,我们将会在你追寻的道路上帮助你',
                style: TextStyle(
                    color:Colors.black54,
                    fontSize: 16,
                    decoration: TextDecoration.none
                ),
                textAlign: TextAlign.center,
              ),
            ),
            SizedBox(height: 35),
            //分页指示器
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Container(
                  height: 11,
                  width: 11,
                  child: CircleAvatar(),
                ),
                SizedBox(width: 10,),
                Container(
                  height: 10,
                  width: 10,
                  child: CircleAvatar(backgroundColor: Theme.of(context).primaryColor.withOpacity(0.1)),
                ),
                SizedBox(width: 10,),
                Container(
                  height: 10,
                  width: 10,
                  child: CircleAvatar(backgroundColor:Theme.of(context).primaryColor.withOpacity(0.1)),
                ),
              ],
            ),

然后是两个按钮,个人认为返回键没有存在的必要,点击下一步可以进入p2

//两个按钮
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                SizedBox(
                  height: 50,
                  width: 100,
                  child:FlatButton(
                    child: Text('返回',style:TextStyle(fontSize: 16,color: Colors.black54)),
                    onPressed:(){},
                    color: Theme.of(context).primaryColor.withOpacity(0.06),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(50),
                    ),
                  ),
                ),
                SizedBox(width: 50,),
                SizedBox(
                  height: 50,
                  width: 100,
                  child:FlatButton(
                    child: Text('下一步',style:TextStyle(fontSize: 16,color: Colors.white)),
                    onPressed:(){
                      Navigator.of(context).push(
                        MaterialPageRoute(builder: (context)=>Target2()),
                      );
                    },
                    color: Theme.of(context).primaryColor,
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(50),
                    ),
                  ),
                )
              ],
            )

所以我做好了第一个页面↓字体什么的都还没设置

然后进入p2,在p1的基础上,把p1的文本框改成了一个IconButton,

IconButton(
                            icon: Icon(Icons.add_circle),
                            iconSize: 100,
                            color: Theme.of(context).primaryColor,
                            splashColor: Colors.transparent,
                            focusColor: Theme.of(context).primaryColor.withOpacity(0.9),
                            onPressed: (){
                              showModalBottomSheet(
                                backgroundColor: Theme.of(context).primaryColor,
                                shape: RoundedRectangleBorder(
                                    borderRadius: BorderRadius.only(
                                      topRight: Radius.circular(40),
                                      topLeft: Radius.circular(40)
                                    )
                                ),
                                context: context,
                                builder: (BuildContext context){
                                   return BottomPage();
                                }
                              );
                            },
                          ),

点击iconButton,弹出如p3所示的选项页面,我就做到这里啦,还没有细化完成。

class BottomPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      height: double.infinity/2,
      padding: EdgeInsets.all(32.0),
    );
  }
}

所以p2 p3的展示:

re8i6O.png re8i6O.png

猜你喜欢

转载自blog.csdn.net/s_h_e_l_l_e_y/article/details/111109075