はじめに
flutter勉強中です。
CustomPaintを使って何か作ってみたかったため、ハンバーガーメニューを自作してみました。
完成品

コード(全体)
main.dart
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Widget _widget = Center(
child: Text('item1',style: TextStyle(fontSize: 24)),
);
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Test'),
elevation: 0.0,
leading: IconButton(
onPressed: () {
setState(() {
_isExpanded ? _isExpanded = false : _isExpanded = true;
});
},
icon: Icon(Icons.menu),
),
),
body: _isExpanded
? customHamburger(
onClick: (Widget widget) {
setState(() {
_widget = widget;
});
},
display: _widget
)
: Container(
child: _widget,
),
),
);
}
}
class item1 {
Widget display() {
return Center(
child: Text('item1',style: TextStyle(fontSize: 24)),
);
}
}
class item2 {
Widget display() {
return Center(
child: Text('item2',style: TextStyle(fontSize: 24)),
);
}
}
class item3 {
Widget display() {
return Center(
child: Text('item3',style: TextStyle(fontSize: 24)),
);
}
}
class item4 {
Widget display() {
return Center(
child: Text('item4',style: TextStyle(fontSize: 24)),
);
}
}
typedef customHamburgerCallback(Widget widget);
class customHamburger extends StatefulWidget{
customHamburgerCallback? onClick;
Widget? display;
customHamburger({@required this.onClick,@required this.display});
@override
_customHamburger createState() => _customHamburger();
}
class _customHamburger extends State<customHamburger>{
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
child: widget.display,
),
Container(
width: 200,
height: 200,
child: CustomPaint(
painter: CanvasPainter(),
)
),
Positioned(
left: 100,
top: 0,
child: Transform.rotate(
angle: 0,
child: TextButton(onPressed: () { widget.onClick!(item1().display());},
child: Text('item1',style: TextStyle(fontSize: 24, color: Colors.white)),
)
)
),
Positioned(
left: 80,
top: 55,
child: Transform.rotate(
angle: math.pi/6,
child: TextButton(onPressed: () { widget.onClick!(item2().display());},
child: Text('item2',style: TextStyle(fontSize: 24, color: Colors.white)),
)
)
),
Positioned(
left: 40,
top: 100,
child: Transform.rotate(
angle: math.pi/3,
child: TextButton(onPressed: () { widget.onClick!(item3().display());},
child: Text('item3',style: TextStyle(fontSize: 24, color: Colors.white)),
)
)
),
Positioned(
left: -20,
top: 130,
child: Transform.rotate(
angle: math.pi/2,
child: TextButton(onPressed: () { widget.onClick!(item4().display());},
child: Text('item4',style: TextStyle(fontSize: 24, color: Colors.white)),
)
)
),
],
);
}
}
class CanvasPainter extends CustomPainter {
//CanvasPainter();
@override
void paint(Canvas canvas, Size size) {
final canvasSize = Rect.fromLTWH(0,0,size.width,size.height);
final rect = Rect.fromLTRB(-200, -200, 200, 200);
final startAngle = 0.0;
final sweepAngle = 6.3;
final useCenter = false;
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill
..strokeWidth = 4;
//canvas.drawRect(canvasSize,paint);
//canvas.drawRect(rect,paint);
canvas.drawArc(rect, startAngle, sweepAngle, useCenter, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
説明
自分用へのメモです。
ポイントとなる処理は以下コードです。
StackとPositionedウィジットにより扇型の土台、メニュー(item1〜4のボタン)を重ね合わせて表示しています。
プログラムは微妙ですが、メモとして残しておきます。
微妙なとこ
・扇型の土台やメニューを重ね合わせる位置、メニューを傾ける角度は適当な数値を入れていますが、数式化できるといい。
・似たような処理が多いので、もう少し綺麗に書けそう。
main.dart
class _customHamburger extends State<customHamburger>{
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Container(
child: widget.display,
),
Container(
width: 200,
height: 200,
child: CustomPaint(
painter: CanvasPainter(),
)
),
Positioned(
left: 100,
top: 0,
child: Transform.rotate(
angle: 0,
child: TextButton(onPressed: () { widget.onClick!(item1().display());},
child: Text('item1',style: TextStyle(fontSize: 24, color: Colors.white)),
)
)
),
Positioned(
left: 80,
top: 55,
child: Transform.rotate(
angle: math.pi/6,
child: TextButton(onPressed: () { widget.onClick!(item2().display());},
child: Text('item2',style: TextStyle(fontSize: 24, color: Colors.white)),
)
)
),
Positioned(
left: 40,
top: 100,
child: Transform.rotate(
angle: math.pi/3,
child: TextButton(onPressed: () { widget.onClick!(item3().display());},
child: Text('item3',style: TextStyle(fontSize: 24, color: Colors.white)),
)
)
),
Positioned(
left: -20,
top: 130,
child: Transform.rotate(
angle: math.pi/2,
child: TextButton(onPressed: () { widget.onClick!(item4().display());},
child: Text('item4',style: TextStyle(fontSize: 24, color: Colors.white)),
)
)
),
],
);
}
}
コメント