颤动设计曲线布局作为单个小部件 [英] flutter design Curves layout as single widget

查看:16
本文介绍了颤动设计曲线布局作为单个小部件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用它时遇到了问题,因为屏幕右侧的这条曲线不是小部件,当我想在绿色一侧有一些其他小部件时,我不能,因为设计的曲线不是小部件,它是从绿色中剪裁的布局.

假设我想在屏幕右侧有这条曲线,在下方有一些小部件.

源代码

import 'package:flutter/material.dart';无效的主要(){runApp(MaterialApp(home: Scaffold(body: Test())));}类测试扩展 StatefulWidget {@覆盖_TestState createState() =>_TestState();}类 _TestState 扩展了状态<Test>{双 _height = 0.0;双 _width = 0.0;双 _rightPadding = 2.0;双 _btnSize = 25.0;双 _btnY = 0.0;@覆盖小部件构建(BuildContext 上下文){如果 (_height == 0.0)设置状态((){_height = MediaQuery.of(context).size.height;_width = MediaQuery.of(context).size.width;_btnY = _height/3 * 2;});返回 _height == 0.0?容器(): 堆(孩子们:<小部件>[容器(颜色:颜色.白色,),自定义油漆(尺寸:尺寸(_width - _rightPadding,_height),画家:CurvedPainter(_btnSize,_btnY),),],);}}类 CurvedPainter 扩展 CustomPainter {CurvedPainter(this.btnSize, this.btnY);最终双 btnSize;最终双 btnY;@覆盖无效油漆(帆布画布,尺寸大小){路径 path = Path();path.moveTo(0.0, 0.0);path.lineTo(size.width, 0.0);path.lineTo(size.width, btnY - btnSize * 2);path.cubicTo(size.width, btnY - btnSize * 0.3, size.width - btnSize * 0.95, btnY - btnSize * 0.9, size.width - btnSize, btnY);path.cubicTo(size.width - btnSize * 0.95, btnY + btnSize * 0.9, size.width, btnY + btnSize * 0.3, size.width, btnY + btnSize * 2);path.lineTo(size.width, size.height);path.lineTo(0.0, size.height);path.lineTo(0.0, 0.0);画布.drawPath(小路,画()..color = 颜色.透明..style = 绘画风格.fill);}@覆盖bool shouldRepaint(CurvedPainter oldDelegate) =>oldDelegate.btnY != btnY;}

我想在所有小部件之上使用右曲线作为小部件,没有绿色边,你假设绿色边是 ListView.

解决方案

您似乎需要下图中给出的类似的东西.

更新:添加了拖动控件

import 'dart:math' as math;导入包:颤振/material.dart";无效的主要()=>运行应用程序(我的应用程序());MyApp 类扩展 StatelessWidget {@覆盖小部件构建(BuildContext 上下文){返回材料应用程序(debugShowCheckedModeBanner:假,标题:颤振演示",主题:主题数据(primarySwatch:颜色.蓝色,),家:脚手架(正文:测试(),),);}}类测试扩展 StatefulWidget {@覆盖_TestState createState() =>_TestState();}枚举拖动类型 { 垂直,水平 }类 _TestState 扩展了状态<Test>{最终双 _btnSize = 48.0;最终双 _rightPadding = 0;双 _extraOffcet = 0;双_btnY;双 _currentX;双 _currentY;双倍高度;双宽度;bool _isHorizo​​ntalActive = true;bool _isVerticalActive = true;@覆盖无效初始化状态(){WidgetsBinding.instance.addPostFrameCallback(_afterLayout);super.initState();}_afterLayout(_)​​ {_height = MediaQuery.of(context).size.height;_width = MediaQuery.of(context).size.width;_btnY = _height/2;setState(() {});}_onDrag(详细信息){_updateCoordinates(details.globalPosition.dx,details.globalPosition.dy,);}_updateCoordinates(双 x, 双 y) {设置状态((){如果(_isHorizo​​ntalActive){_updateX(x);}如果(_isVerticalActive){_updateY(y);}});}_updateX(x) {var dx = _currentX - x;_currentX = x;_extraOffcet = _extraOffcet + dx;_extraOffcet = math.max(_extraOffcet, _rightPadding);_extraOffcet = math.min(_extraOffcet, _width - _btnSize);}_updateY(y) {var dy = _currentY - y;_currentY = y;_btnY = _btnY - dy;_btnY = math.max(_btnY, _btnSize);_btnY = math.min(_btnY, _height - _btnSize);}_listItem(字符串文本,双倍高度){返回容器(高度:高度,孩子:文本(文本,样式:TextStyle(字体大小:20.0)),);}@覆盖小部件构建(BuildContext 上下文){返回 _height == null?容器(): 堆(孩子们:<小部件>[容器(填充:EdgeInsets.only(右:30),颜色:颜色.蓝色,高度:双无限,宽度:双无限,孩子:列(mainAxisAlignment:MainAxisAlignment.center,孩子:[_buildSwitch(类型:dragType.vertical),_buildSwitch(类型:dragType.horizo​​ntal),...列表.生成(4、(索引)=>_listItem('内部', 80),),]),),定位(右:_extraOffcet + _rightPadding,孩子:自定义油漆(尺寸:尺寸(_btnSize,_height),画家:CurvedPainter(_btnSize,_btnY),),),定位(顶部:_btnY - _btnSize/2 + 5,右:_extraOffcet + _rightPadding + 5,孩子:手势检测器(onPanDown:(详细信息){_currentX = details.globalPosition.dx;_currentY = details.globalPosition.dy;},onPanStart: _onDrag,onPanUpdate: _onDrag,孩子:材料(类型:MaterialType.circle,颜色:颜色.白色,海拔:8.0,孩子:容器(宽度:_btnSize - 10,高度:_btnSize - 10,孩子:图标(Icons.add),),),),),定位(顶部:0,左:_width - _extraOffcet,孩子:容器(颜色:颜色.白色,孩子:列(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment:CrossAxisAlignment.start,孩子: List.generate(8, (index) => _listItem('from right', 20)),),高度:_高度,宽度:_width,),),],);}SwitchListTile _buildSwitch({dragType type}) {函数 onChange;字符串标题文本,标题文本;布尔值;if (type == dragType.horizo​​ntal) {值 = _isHorizo​​ntalActive;titleText = '水平拖动';onChange = (newValue) =>setState(() => _isHorizo​​ntalActive = newValue);} 别的 {值 = _isVerticalActive;titleText = '垂直拖动';onChange = (newValue) =>setState(() => _isVerticalActive = newValue);}字幕文本 = 价值?活动":禁用";返回 SwitchListTile(价值:价值,onChanged: onChange,标题:文本(titleText),副标题:文本(sutitleText),);}}类 CurvedPainter 扩展 CustomPainter {CurvedPainter(this.btnSize, this.btnY);最终双 btnSize;最终双 btnY;@覆盖无效油漆(帆布画布,尺寸大小){var halfBtnSize = btnSize/2;var xMax = size.width;var yMax = size.height;变量路径 = 路径()..moveTo(halfBtnSize, yMax)..lineTo(halfBtnSize, btnY + halfBtnSize * 2)..cubicTo(halfBtnSize, btnY + halfBtnSize, 0, btnY + halfBtnSize, 0, btnY)..cubicTo(0, btnY - halfBtnSize, halfBtnSize, btnY - halfBtnSize, halfBtnSize,btnY - halfBtnSize * 2)..lineTo(halfBtnSize, 0)..lineTo(xMax, 0)..lineTo(xMax, yMax);画布.drawPath(小路,画()..color = 颜色.white..style = 绘画风格.fill);}@覆盖bool shouldRepaint(CurvedPainter oldDelegate) =>oldDelegate.btnY != btnY;}

Here solved question about design this layout.

I have a problem to using that, because of this curve on right of screen is not widget and when I want to have some other widgets in green side, I can't, because designed curve is not widget its clipped from green layout.

Suppose I want to have this curve on right of screen and some widget in below of that.

Source code

import 'package:flutter/material.dart';

void main() {
    runApp(MaterialApp(home: Scaffold(body: Test())));
}

class Test extends StatefulWidget {
    @override
    _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
    double _height = 0.0;
    double _width = 0.0;
    double _rightPadding = 2.0;
    double _btnSize = 25.0;
    double _btnY = 0.0;

    @override
    Widget build(BuildContext context) {
    if (_height == 0.0)
        setState(() {
        _height = MediaQuery.of(context).size.height;
        _width = MediaQuery.of(context).size.width;
        _btnY = _height / 3 * 2;
        });
    return _height == 0.0
        ? Container()
        : Stack(
            children: <Widget>[
                Container(
                color: Colors.white,
                ),
                CustomPaint(
                size: Size(_width - _rightPadding, _height),
                painter: CurvedPainter(_btnSize, _btnY),
                ),
            ],
            );
    }
}

class CurvedPainter extends CustomPainter {
    CurvedPainter(this.btnSize, this.btnY);

    final double btnSize;
    final double btnY;

    @override
    void paint(Canvas canvas, Size size) {
    Path path = Path();
    path.moveTo(0.0, 0.0);
    path.lineTo(size.width, 0.0);
    path.lineTo(size.width, btnY - btnSize * 2);

    path.cubicTo(size.width, btnY - btnSize * 0.3, size.width - btnSize * 0.95, btnY - btnSize * 0.9, size.width - btnSize, btnY);
    path.cubicTo(size.width - btnSize * 0.95, btnY + btnSize * 0.9, size.width, btnY + btnSize * 0.3, size.width, btnY + btnSize * 2);

    path.lineTo(size.width, size.height);
    path.lineTo(0.0, size.height);
    path.lineTo(0.0, 0.0);
    canvas.drawPath(
        path,
        Paint()
            ..color = Colors.transparent
            ..style = PaintingStyle.fill);
    }

    @override
    bool shouldRepaint(CurvedPainter oldDelegate) => oldDelegate.btnY != btnY;
}

I want to use right curve as an widget on top of all widgets, without having green side, you suppose green side is as ListView.

解决方案

It seems that you need something like this given in the image below.

Update: Dragging control added

import 'dart:math' as math;
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: Test(),
      ),
    );
  }
}

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

enum dragType { vertical, horizontal }

class _TestState extends State<Test> {
  final double _btnSize = 48.0;
  final double _rightPadding = 0;

  double _extraOffcet = 0;
  double _btnY;
  double _currentX;
  double _currentY;
  double _height;
  double _width;

  bool _isHorizontalActive = true;
  bool _isVerticalActive = true;

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);

    super.initState();
  }

  _afterLayout(_) {
    _height = MediaQuery.of(context).size.height;
    _width = MediaQuery.of(context).size.width;
    _btnY = _height / 2;
    setState(() {});
  }

  _onDrag(details) {
    _updateCoordinates(
      details.globalPosition.dx,
      details.globalPosition.dy,
    );
  }

  _updateCoordinates(double x, double y) {
    setState(() {
      if (_isHorizontalActive) {
        _updateX(x);
      }
      if (_isVerticalActive) {
        _updateY(y);
      }
    });
  }

  _updateX(x) {
    var dx = _currentX - x;
    _currentX = x;
    _extraOffcet = _extraOffcet + dx;
    _extraOffcet = math.max(_extraOffcet, _rightPadding);
    _extraOffcet = math.min(_extraOffcet, _width - _btnSize);
  }

  _updateY(y) {
    var dy = _currentY - y;
    _currentY = y;
    _btnY = _btnY - dy;
    _btnY = math.max(_btnY, _btnSize);
    _btnY = math.min(_btnY, _height - _btnSize);
  }

  _listItem(String text, double height) {
    return Container(
      height: height,
      child: Text(text, style: TextStyle(fontSize: 20.0)),
    );
  }

  @override
  Widget build(BuildContext context) {
    return _height == null
        ? Container()
        : Stack(
            children: <Widget>[
              Container(
                padding: EdgeInsets.only(right: 30),
                color: Colors.blue,
                height: double.infinity,
                width: double.infinity,
                child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
                  _buildSwitch(type: dragType.vertical),
                  _buildSwitch(type: dragType.horizontal),
                  ...List.generate(
                    4,
                    (index) => _listItem('inside', 80),
                  ),
                ]),
              ),
              Positioned(
                right: _extraOffcet + _rightPadding,
                child: CustomPaint(
                  size: Size(_btnSize, _height),
                  painter: CurvedPainter(_btnSize, _btnY),
                ),
              ),
              Positioned(
                top: _btnY - _btnSize / 2 + 5,
                right: _extraOffcet + _rightPadding + 5,
                child: GestureDetector(
                  onPanDown: (details) {
                    _currentX = details.globalPosition.dx;
                    _currentY = details.globalPosition.dy;
                  },
                  onPanStart: _onDrag,
                  onPanUpdate: _onDrag,
                  child: Material(
                    type: MaterialType.circle,
                    color: Colors.white,
                    elevation: 8.0,
                    child: Container(
                      width: _btnSize - 10,
                      height: _btnSize - 10,
                      child: Icon(Icons.add),
                    ),
                  ),
                ),
              ),
              Positioned(
                top: 0,
                left: _width - _extraOffcet,
                child: Container(
                  color: Colors.white,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: List.generate(8, (index) => _listItem('from right', 20)),
                  ),
                  height: _height,
                  width: _width,
                ),
              ),
            ],
          );
  }

  SwitchListTile _buildSwitch({dragType type}) {
    Function onChange;
    String titleText, sutitleText;
    bool value;

    if (type == dragType.horizontal) {
      value = _isHorizontalActive;
      titleText = 'Horizontal dragging';
      onChange = (newValue) => setState(() => _isHorizontalActive = newValue);
    } else {
      value = _isVerticalActive;
      titleText = 'Vertical dragging';
      onChange = (newValue) => setState(() => _isVerticalActive = newValue);
    }
    sutitleText = value ? 'active' : 'disabled';

    return SwitchListTile(
      value: value,
      onChanged: onChange,
      title: Text(titleText),
      subtitle: Text(sutitleText),
    );
  }
}

class CurvedPainter extends CustomPainter {
  CurvedPainter(this.btnSize, this.btnY);

  final double btnSize;
  final double btnY;

  @override
  void paint(Canvas canvas, Size size) {
    var halfBtnSize = btnSize / 2;
    var xMax = size.width;
    var yMax = size.height;

    var path = Path()
      ..moveTo(halfBtnSize, yMax)
      ..lineTo(halfBtnSize, btnY + halfBtnSize * 2)
      ..cubicTo(halfBtnSize, btnY + halfBtnSize, 0, btnY + halfBtnSize, 0, btnY)
      ..cubicTo(0, btnY - halfBtnSize, halfBtnSize, btnY - halfBtnSize, halfBtnSize,
          btnY - halfBtnSize * 2)
      ..lineTo(halfBtnSize, 0)
      ..lineTo(xMax, 0)
      ..lineTo(xMax, yMax);

    canvas.drawPath(
        path,
        Paint()
          ..color = Colors.white
          ..style = PaintingStyle.fill);
  }

  @override
  bool shouldRepaint(CurvedPainter oldDelegate) => oldDelegate.btnY != btnY;
}

这篇关于颤动设计曲线布局作为单个小部件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆