はじめに
flutter_neumorphicというパッケージを使うと,簡単にアプリの中にニューモフィックデザインを取り入れることができます。
この記事ではこのパッケージで用意されていないタブビューを作成する手順を記したいと思います。
この記事を読んでできること
画像のようにタブ作成しボタンを押すことで画面を切り替えられるようにします。画像ではText("A")を表示しているだけですが,入力フォームなどなんでも表示することができます。
1.NeumorphicButtonを配置する
flutter_neumorphicにはニューモフィックデザインのボタンが用意されているので,それを作成します。
body: Center(
child: NeumorphicButton(
style: NeumorphicStyle(
shape: NeumorphicShape.concave
),
onPressed: (){print("ボタンが押された");},
child: Text("ボタン"),
),
)
これだけで作成できます。なんて素晴らしいパッケージなんだ!
2.AppBarと配置されるビューを準備し,StackとOffStageに入れる。
OffStageを使うことでbool型のパラメータをもとに,falseの時は表示,trueの時は表示といった処理ができます。また,StackはWidgetを重ねることができるため,StackとOffStageを組み合わせることでタブビューを作成することができます。
StackとOffStageの使い方については別のところで記事にしています。
appBar: AppBar(
backgroundColor: Color.fromRGBO(220, 231, 240, 1),
title: Stack(
children: <Widget>[
Offstage(
offstage: !bShow,
child: Container(
child: Text("A",
style: TextStyle(color: Colors.black)),
)
),
Offstage(
offstage: !aShow,
child: Container(
child: Text("B",
style: TextStyle(color: Colors.black)),
)
),
],
)
),
上のコードはaShow,bShowというbool型の値によって,AppBarをそれぞれ入れ替えることができるようにしています。aShow,bShowはタブビューのボタンを押すことでそれぞれ値を反転させればタブビューを表現できます。
3.タブビューのボタンを入れ替えることで真偽値を入れ替えるようにする。
1で作ったボタンのonPressed()にaShow,bShowを反転する処理を書きます。また,ボタンをそれぞれ作成し,Rowに入れます。
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
NeumorphicButton(
child: Container(
width: 30,
height: 30,
child: Text("A")
),
onPressed: (){
aShow = !aShow;
bShow = !bShow;
},
),
NeumorphicButton(
child: Container(
width: 30,
height: 30,
child: Text("B")
),
onPressed: (){
aShow = !aShow;
bShow = !bShow;
},
),
],
)
ソースコード
上のニューモフィックデザイン取り入れたものとは異なりますが,コピペしてそのまま使えるコードを置いておきます。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool showRed = false;
bool showBlue = true;
bool showGreen = true;
void showChange(String color) {
switch(color){
case 'red':
print("赤");
setState(() {
showRed = false;
showBlue = true;
showGreen = true;
});
break;
case 'blue':
print("青");
setState(() {
showRed = true;
showBlue = false;
showGreen = true;
});
break;
case 'green':
print("緑");
setState(() {
showRed = true;
showBlue = true;
showGreen = false;
});
break;
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Center(
child: Stack(
children: <Widget>[
Offstage(
offstage: showRed,
child: Text("赤"),
),
Offstage(
offstage: showBlue,
child: Text("青"),
),
Offstage(
offstage: showGreen,
child: Text("緑"),
),
],
),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(5.0),
child: Stack(
children: <Widget>[
Offstage(
offstage: showRed,
child: Red()
),
Offstage(
offstage: showBlue,
child: Blue()
),
Offstage(
offstage: showGreen,
child: Green()
),
],
),
),
Spacer(),
tabButton(),
],
),
),
),
);
}
Widget tabButton() {
return Container(
//final Size size = MediaQuery.of(context).size;
width: 500,
height: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 100,
height: 100,
child: RaisedButton(
child: Text("赤"),
onPressed: (){
showChange('red');
}
),
),
Container(
width: 100,
height: 100,
child: RaisedButton(
child: Text("青"),
onPressed: (){
showChange('blue');
}
),
),
Container(
width: 100,
height: 100,
child: RaisedButton(
child: Text("緑"),
onPressed: (){
showChange('green');
}
),
),
],
),
);
}
}
class Red extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 400,
height: 400,
color: Colors.red,
child: (
Text("Red")
),
);
}
}
class Blue extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 400,
height: 400,
color: Colors.blue,
child: (
Text("Red")
),
);
}
}
class Green extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 400,
height: 400,
color: Colors.green,
child: (
Text("Red")
),
);
}
}