ほとんどのモバイル アプリケーションには、さまざまな画像が含まれています。
しかし、それらなしではどうですか?画像は、ユーザー インターフェイスをより豊かで明確にします。
Flutter には画像のサポートが組み込まれています。最も一般的に使用されるクラスは Image です。これについては、この記事で説明します。
では行きましょう!
私たちの計画
パート 1 - 開発の紹介、最初の付録、状態の概念。
パート 2 - pubspec.yaml ファイルとコマンド ラインでのフラッターの使用。
パート 3 - BottomNavigationBar とナビゲーター。
パート 4 - MVC。この特定のパターンを最も単純なものの 1 つとして使用します。
パート 5 - http パッケージ。Repository クラスの作成、最初のリクエスト、投稿のリスト。
パート 6 - フォーム、テキスト ボックスの操作、投稿の作成。
パート 7 (現在の記事) - 画像の操作、グリッドの形式での画像の表示、ネットワークからの画像の受信、アプリケーションへの独自の追加。
パート 8 - 独自のテーマを作成し、カスタム フォントとアニメーションを追加します。
パート 9 - テストについて少し。
プロジェクトに写真を追加する
まず、自分の写真をプロジェクトに追加してみましょう。
注意: プロジェクトに画像を追加すると、アプリケーションのサイズが大きくなるので、やりすぎないように注意してください。
画像を追加するにimages
は、プロジェクトのルートに新しいディレクトリを作成する必要があります。
images
pubspec.yaml:
# dependencies: flutter: sdk: flutter # ... # dev_dependencies: # ... # assets flutter: # , MaterialApp # Material Design uses-material-design: true # images # / , # images assets: - images/
. Github':
AlbumListPage
:
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
class AlbumListPage extends StatefulWidget {
@override
_AlbumListPageState createState() => _AlbumListPageState();
}
class _AlbumListPageState extends State<AlbumListPage> {
//
final fileImages = [
"applejack.png",
"fluttershy.png",
"rarity.png",
"starlight_glimmer.png",
"twillight_sparkle.png"
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Album List Page"),
),
body: _buildContent()
);
}
//
Widget _buildContent() {
// flutter_staggered_grid_view
// StaggeredGridView
return StaggeredGridView.countBuilder(
//
itemCount: fileImages.length,
// crossAxisCount
//
crossAxisCount: 8,
//
mainAxisSpacing: 10,
//
crossAxisSpacing: 10,
staggeredTileBuilder: (index) {
// 4 ( )
// 2 ( )
return StaggeredTile.count(4, index % 2 == 0 ? 4 : 8);
},
//
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.pinkAccent, width: 1)
),
// Image.asset
// pubspec.yaml
// asset Image
child: Image.asset("images/${fileImages[index]}"),
);
},
);
}
}
.
! .
REST API .
, AlbumListPage. , , .
.
Photo
:
// Post
class Photo {
final int _id;
final String _title;
final String _url;
Photo.fromJson(Map<String, dynamic> json) :
_id = json["id"],
_title = json["title"],
_url = json["url"];
}
class PhotoList {
final List<Photo> photos = [];
PhotoList.fromJson(List<dynamic> jsonItems) {
for (var jsonItem in jsonItems) {
photos.add(Photo.fromJson(jsonItem));
}
}
}
abstract class PhotoResult {}
class PhotoResultSuccess extends PhotoResult {
final PhotoList photoList;
PhotoResultSuccess(this.photoList);
}
//
class PhotoResultFailure extends PhotoResult {
final String error;
PhotoResultFailure(this.error);
}
//
class PhotoResultLoading extends PhotoResult {
PhotoResultLoading();
}
Repository
:
Future<PhotoList> fetchPhotos() async {
// URL,
//
final url = Uri.parse("$SERVER/photos");
// GET
final response = await http.get(url);
//
if (response.statusCode == 200) {
//
// json.decode
return PhotoList.fromJson(json.decode(response.body));
} else {
//
throw Exception("failed request");
}
}
AlbumController
:
// AlbumController PostController
class AlbumController extends ControllerMVC {
final Repository repo = Repository();
//
PhotoResult currentState = PhotoResultLoading();
void init() async {
try {
//
final photoList = await repo.fetchPhotos();
//
setState(() => currentState = PhotoResultSuccess(photoList));
} catch (error) {
//
setState(() => currentState = PhotoResultFailure(" "));
}
}
}
AlbumListPage
:
class AlbumListPage extends StatefulWidget {
@override
_AlbumListPageState createState() => _AlbumListPageState();
}
class _AlbumListPageState extends StateMVC {
//
// late
late AlbumController _controller;
_AlbumListPageState() : super(AlbumController()){
_controller = controller as AlbumController;
}
@override
void initState() {
super.initState();
// JSONPlaceholder
_controller.init();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Album List Page"),
),
body: _buildContent()
);
}
Widget _buildContent() {
//
final state = _controller.currentState;
if (state is PhotoResultLoading) {
//
return Center(
child: CircularProgressIndicator(),
);
} else if (state is PhotoResultFailure) {
//
return Center(
child: Text(
state.error,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4!.copyWith(color: Colors.red)
),
);
} else {
final images = (state as PhotoResultSuccess).photoList.photos;
// StaggeredGridView
//
return StaggeredGridView.countBuilder(
//
itemCount: images.length,
// crossAxisCount
//
crossAxisCount: 8,
//
mainAxisSpacing: 10,
//
crossAxisSpacing: 10,
staggeredTileBuilder: (index) {
// 4 ( )
// 2 ( )
return StaggeredTile.count(4, index % 2 == 0 ? 4 : 8);
},
//
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.pinkAccent, width: 1)
),
// Image.network
//
child: Image.network(
images[index].url,
//
width: double.infinity,
height: double.infinity,
//
fit: BoxFit.cover,
//
// Loading...
loadingBuilder: (context, widget, imageChunkEvent) {
if (imageChunkEvent == null) {
return widget;
}
return Center(child: Text("Loading..."));
},
//
// Error!
errorBuilder: (context, obj, stacktrace) => Center(child: Text("Error!")),
),
);
},
);
}
}
}
.
!
, Flutter .
Image.network
は万能薬ではないため、戦闘プロジェクトではより多くの機能を備えた特別なライブラリを使用することをお勧めします。
これらの有望なライブラリの 1 つはcached_network_image です。
これは、すべての技術的な問題と複雑さを処理するかなり単純なライブラリです。
便利なリンク:
皆さん良いコードを!