👠
CustomScrollViewを使ってみた
SNS風のUIを作るのに使ってみた
SNS風と書いてますが、オシャレではないです😅
今回はこちらのWidgetを使用 スライバーを使用してカスタムスクロールエフェクトを作成するScrollView。
CustomScrollView を使用すると、リスト、グリッド、拡大ヘッダーなどの様々なスクロールエフェクトを作成するためにスリバーを直接指定することができます。例えば、拡張アプリバーに続いてリストとグリッドを含むスクロールビューを作成するには、3つのスリバーのリストを使用します:SliverAppBar、SliverList、SliverGrid です。
これらのスリバー内のウィジェットは、RenderSliver オブジェクトを生成する必要があります。
スクロールビューの初期スクロールオフセットを制御するには、ScrollController.initialScrollOffset プロパティを設定したコントローラを提供します。
APIのデータをUIに表示してるので追加
実際に使ってみる
APIからデータを取得するときに、使うモデルクラス
モデルクラス
model.dart
// postsからデータを取得するモデルクラス
class Post {
final String title;
final String body;
Post({required this.title, required this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
title: json['title'],
body: json['body'],
);
}
}
// albumsからデータを取得するモデルクラス
class Album {
final String title;
Album({required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
title: json['title'],
);
}
}
CustomScrollViewを使用して、作成した複雑なUI
SNS風のUI
main.dart
import 'package:custom_view/model.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(SNSApp());
}
class SNSApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SNS UI',
theme: ThemeData(primarySwatch: Colors.blue),
home: SNSHomePage(),
);
}
}
class SNSHomePage extends StatefulWidget {
const SNSHomePage({super.key});
@override
_SNSHomePageState createState() => _SNSHomePageState();
}
class _SNSHomePageState extends State<SNSHomePage> {
// Postモデルクラスのリスト
List<Post> posts = [];
// Albumモデルクラスのリスト
List<Album> albums = [];
@override
void initState() {
super.initState();
// initState()メソッドでfetchData()メソッドを呼び出す
fetchData();
}
// APIからデータを取得するメソッド
Future<void> fetchData() async {
final postsResponse =
await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
final albumsResponse = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums'));
if (postsResponse.statusCode == 200 && albumsResponse.statusCode == 200) {
setState(() {
posts = (json.decode(postsResponse.body) as List<dynamic>)
.map((json) => Post.fromJson(json))
.toList();
albums = (json.decode(albumsResponse.body) as List<dynamic>)
.map((json) => Album.fromJson(json))
.toList();
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
// CustomScrollViewは、SliverAppBarやSliverList、SliverGridなどのウィジェットを組み合わせて使う
body: CustomScrollView(
slivers: <Widget>[
// SliverAppBarは、AppBarのように画面上部に配置されるヘッダーを作成する
const SliverAppBar(
pinned: true,
expandedHeight: 80.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Demo'),
),
),
// SliverListは、ListViewのようにリストを作成する
SliverList(
delegate: SliverChildListDelegate([
Container(
height: 200.0,
color: Colors.grey[300],
child: Center(
child: Icon(
Icons.account_circle,
size: 100.0,
color: Colors.grey[500],
),
),
),
// ListTileは、リストのアイテムを作成する
ListTile(
leading: Icon(Icons.person),
title: Text('User Name'),
),
Divider(),
ListTile(
leading: Icon(Icons.photo),
title: Text('Photos'),
),
ListTile(
leading: Icon(Icons.video_library),
title: Text('Videos'),
),
ListTile(
leading: Icon(Icons.article),
title: Text('Articles'),
),
ListTile(
leading: Icon(Icons.group),
title: Text('Groups'),
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
),
]),
),
// SliverGridは、GridViewのようにグリッドを作成する
SliverGrid(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index < albums.length) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 3)],
child: Text(albums[index].title),
);
} else {
return null;
}
},
childCount: albums.length,
),
),
// SliverFixedExtentListは、ListViewのようにリストを作成する
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index < posts.length) {
return Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 3)],
child: Text(posts[index].title),
);
} else {
return null;
}
},
childCount: posts.length,
),
),
],
),
);
}
}
コードの解説
- SliverAppBarは、AppBarのように、画面上部に表示されるヘッダーとして使う
SliverAppBar(
pinned: true,
expandedHeight: 80.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Demo'),
),
),
- SliverListは、ListViewと同じように使う
SliverList(
delegate: SliverChildListDelegate([
Container(
height: 200.0,
color: Colors.grey[300],
child: Center(
child: Icon(
Icons.account_circle,
size: 100.0,
color: Colors.grey[500],
),
),
),
// ListTileは、リストのアイテムを作成する
ListTile(
leading: Icon(Icons.person),
title: Text('User Name'),
),
Divider(),
ListTile(
leading: Icon(Icons.photo),
title: Text('Photos'),
),
ListTile(
leading: Icon(Icons.video_library),
title: Text('Videos'),
),
ListTile(
leading: Icon(Icons.article),
title: Text('Articles'),
),
ListTile(
leading: Icon(Icons.group),
title: Text('Groups'),
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
),
]),
),
- SliverGridは、GridViewのようにグリッドを作成する
SliverGrid(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 1.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index < albums.length) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 3)],
child: Text(albums[index].title),
);
} else {
return null;
}
},
childCount: albums.length,
),
),
- SliverFixedExtentListは、ListViewのようにリストを作成する
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index < posts.length) {
return Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 3)],
child: Text(posts[index].title),
);
} else {
return null;
}
},
childCount: posts.length,
),
),
🦾こんな感じのUIが作れました



まとめ
CustomScrollViewを使用すれば、ListViewやGridViewを組み合わせて、複雑なUIを作り出すことができます。投稿画像や投稿した文章を同じページで、複数表示するのに、向いています。
Discussion