![見出し画像](https://assets.st-note.com/production/uploads/images/25207416/rectangle_large_type_2_c502d3b588dc3ed7ca28cce855102b66.jpeg?width=800)
CardとListTileっぽいWidgetの書き方
FlutterのCardとListTileを使えばよくあるこんなカード型のViewがかんたんに実現できます。
ですが、実現したいデザインと少し違う場合は、ListTileを使わずにColumnとRowを組み合わせることになると思います。公式のListTileクラスでサンプルを確認できます。
ContainerとColumnとRowを組み合わせた素振りをしてみます。以下のようなデザインにしたいと思います。
・カードをタップしたらリップルエフェクトを効かせる
・リップルエフェクトの色とカード背景色をそれぞれ指定したい
・カードは角丸&シャドウをつける
・画像はウェブからダウンロードして表示する
ColumnとRowのレイアウト
Rowで画像とテキスト領域を縦分割し、テキスト領域はColumnで積み重ねていきます。RowとColumnのmainAxisAlignmentはMainAxisAlignment.startにすると、Rowは左寄り、Columnは上寄りに配置されます。デフォルトがMainAxisAlignment.startなので書かなくてもOKです。
ColumnのcrossAxisAlignmentをCrossAxisAlignment.startにしてテキストを左寄せにします。
覚えてしまえばゴリゴリかけますが、慣れないうちはチートシートにお世話になります。
マージンを取る方法はいろいろありますが、RowやColumnの場合はSizedBox()を使うのが一般的かもしれません。HTMLのような書き方を踏襲するとpaddingやmarginをセットするためにContainerやPaddingでラップしますが、ネストが深くなり見づらいので好みではありません。
リップルエフェクトをつける
カードをタップしたい且つリップルエフェクトを効かせたい場合、MaterialとInkWellを使います。InkWellのsplashColorでリップルエフェクトの色を指定できます。なお、GestureDetectorでもタップ機能を実現できますがエフェクトがありません。
リップルエフェクトは背景色の効果なので、その効果を描画するInkWellの上に背景色をもつWidgetを乗せると、そのWidget上にリップルエフェクトは描画されません。つまり、画像の上にはリップルエフェクトが描画されないことになります。
Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(10),
splashColor: Color(0x30f010f0),
onTap: () => print('tap!'),),)
角丸とシャドウをつける
Containerのdecorationを指定するだけではなく、画像の左上と左下を丸める必要があります。画像のクリッピングはClipRRectを使います。
ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10)),
child: Image())
画像を表示する
ウェブ上の画像を表示するのはImage.networkで可能です。
Image.network('https://picsum.photos/200', width: 100, height: 100)
サンプルコード
class SampleCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.green[100],
borderRadius: BorderRadius.circular(10),
boxShadow: [
const BoxShadow(
color: Color(0x80000000),
offset: Offset(0, 4),
blurRadius: 6,
)
],
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(10),
splashColor: Color(0x30f010f0),
onTap: () => print('tap!'),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10),
),
child: Image.network(
'https://picsum.photos/200',
width: 100,
height: 100,
)),
SizedBox(
width: 10,
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 10),
Text(
'Title',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: const Color(0xff333333),
),
),
Text(
'Test description!',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.normal,
color: const Color(0xff333333),
),
),
]),
],
),
),
),
);
}
}
この記事が気に入ったらサポートをしてみませんか?