最後に、最も重要なトピックの 1 つに到達しました。これがなければ、先に進む意味がありません。
計画は非常に単純です。クライアント サーバー アーキテクチャに精通し、投稿のリストを実装する必要があります。
最後に、ページ ファイルを適切に整理し、リスト アイテムを別のファイルに移動します。
飛ぼう!
私たちの計画
パート 1 - 開発の紹介、最初の付録、状態の概念。
パート 2 - pubspec.yaml ファイルとコマンド ラインでのフラッターの使用。
パート 3 - BottomNavigationBar とナビゲーター。
パート 4 - MVC。この特定のパターンを最も単純なものの 1 つとして使用します。
パート 5 (現在の記事) - http パッケージ。Repository クラスの作成、最初のリクエスト、投稿のリスト。
パート 6 - フォーム、テキスト ボックスの操作、投稿の作成。
パート 7 - 画像の操作、グリッドの形式での画像の表示、ネットワークからの画像の受信、独自の画像のアプリケーションへの追加。
パート 8 - 独自のテーマを作成し、カスタム フォントとアニメーションを追加します。
パート 9 - テストについて少し。
クライアントとサーバー
クライアント/サーバーモデルは、インターネット全体の中心であり、最も普及しています。
その本質とは?
まず、クライアントとサーバーが何であるかを理解しましょう。
クライアント - サーバーへの要求を送信し、応答を受信するユーザー デバイス。スマートフォンでも、コンピューターでも、MacBook でもかまいません。
サーバーは、ユーザーが必要とするデータを含む特別なコンピューターです。
モデル全体は、基本的な原則に要約されます。つまり、クライアントがリクエストを送信し、サーバーがリクエストを受け取り、それを処理して、クライアントにレスポンスを送信します。
サーバーとクライアント間の対話を編成するために、特別なプロトコルが使用されます。現在、インターネットで最も一般的なプロトコルの 1 つはhttp / https (s はセキュアを意味します) です。
http / https を使用すると、ほぼすべての既知のデータ形式 (写真、ビデオ、テキスト) を転送できます。
JSON形式で作業します。
JSONはシンプルで理解しやすいデータ形式であり、最も重要なのは軽量です。テキストのみが送信されます。
JSON の例:
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
},
...
]
サーバーから受信する投稿の配列を次に示します。
: , .
JSON :
{
"total_items" : 1
"result" : [
{
"id" : 1,
"name" : "Twillight Sparkle",
"pony_type" : "alicorn",
"friends" : [
"Starlight Glimmer", "Applejack", "Rarity", "Spike"
]
}
]
}
.
.. http / https HTTP .
HTTP :
URL - , , . URL : https://jsonplaceholder.typicode.com/posts. ( URL' )
, . GET , POST , DELETE - , PUT - .
POST, PUT DELETE . GET URL'. : https://jsonplaceholder.typicode.com/posts/1 ( id = 1)
http
.
, pubspec.yaml
:
# dependencies: flutter: sdk: flutter # pub- # # flutter_staggered_grid_view: ^0.4.0 # MVC mvc_pattern: ^7.0.0 # http # http: ^0.13.3
.
post.dart
models
:
//
class Post {
// private
//
final int _userId;
final int _id;
final String _title;
final String _body;
// getters
//
int get userId => _userId;
int get id => _id;
String get title => _title;
String get body => _body;
// Dart
// Post.fromJson(json) -
// JSON
// , dynamic
// : String, int, double ..
Post.fromJson(Map<String, dynamic> json) :
this._userId = json["userId"],
this._id = json["id"],
this._title = json["title"],
this._body = json["body"];
}
// PostList
class PostList {
final List<Post> posts = [];
PostList.fromJson(List<dynamic> jsonItems) {
for (var jsonItem in jsonItems) {
posts.add(Post.fromJson(jsonItem));
}
}
}
//
//
//
abstract class PostResult {}
//
class PostResultSuccess extends PostResult {
final PostList postList;
PostResultSuccess(this.postList);
}
//
class PostResultFailure extends PostResult {
final String error;
PostResultFailure(this.error);
}
//
class PostResultLoading extends PostResult {
PostResultLoading();
}
.
JSON :
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
, userId
id
, title
body
, Post.fromJson(json)
.
Repository
.
data
repository.dart
:
import 'dart:convert';
// http
import 'package:http/http.dart' as http;
import 'package:json_placeholder_app/models/post.dart';
//
// SERVER
const String SERVER = "https://jsonplaceholder.typicode.com";
class Repository {
//
// Future ,
// fetchPhotos
// UI
Future<PostList> fetchPosts() async {
// URL,
//
final url = Uri.parse("$SERVER/posts");
// GET
final response = await http.get(url);
//
if (response.statusCode == 200) {
//
// json.decode
return PostList.fromJson(json.decode(response.body));
} else {
//
throw Exception("failed request");
}
}
}
: , ?
.. , .
. URL .
PostController
:
import '../data/repository.dart';
import '../models/post.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
class PostController extends ControllerMVC {
//
final Repository repo = new Repository();
//
PostController();
// -
PostResult currentState = PostResultLoading();
void init() async {
try {
//
final postList = await repo.fetchPosts();
//
setState(() => currentState = PostResultSuccess(postList));
} catch (error) {
//
setState(() => currentState = PostResultFailure(" "));
}
}
}
: :
import 'package:flutter/material.dart';
import '../controllers/post_controller.dart';
import '../models/post.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
class PostListPage extends StatefulWidget {
@override
_PostListPageState createState() => _PostListPageState();
}
// StateMVC
class _PostListPageState extends StateMVC {
//
PostController _controller;
// StateMVC
//
_PostListPageState() : super(PostController()) {
_controller = controller as PostController;
}
//
//
@override
void initState() {
super.initState();
_controller.init();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Post List Page"),
),
body: _buildContent()
);
}
Widget _buildContent() {
//
final state = _controller.currentState;
if (state is PostResultLoading) {
//
return Center(
child: CircularProgressIndicator(),
);
} else if (state is PostResultFailure) {
//
return Center(
child: Text(
state.error,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4.copyWith(color: Colors.red)
),
);
} else {
//
final posts = (state as PostResultSuccess).postList.posts;
return Padding(
padding: EdgeInsets.all(10),
// ListView.builder
//
child: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
return _buildPostItem(posts[index]);
},
),
);
}
}
//
Widget _buildPostItem(Post post) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
border: Border.all(color: Colors.grey.withOpacity(0.5), width: 0.3)
),
margin: EdgeInsets.only(bottom: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15)),
color: Theme.of(context).primaryColor,
),
padding: EdgeInsets.all(10),
child: Text(
post.title,
textAlign: TextAlign.left,
style: Theme.of(context).textTheme.headline5.copyWith(color: Colors.white),),
),
Container(
child: Text(
post.body,
style: Theme.of(context).textTheme.bodyText2,
),
padding: EdgeInsets.all(10),
),
],
)
);
}
}
.
, )
:
! :
!
.
post_list_page.dart
110 , . 10 20 !
, .
.
Widget _buildItem(post)
.
:
post post_list_item.dart:
import 'package:flutter/material.dart';
import '../../models/post.dart';
//
class PostListItem extends StatelessWidget {
final Post post;
//
PostListItem(this.post);
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
border: Border.all(color: Colors.grey.withOpacity(0.5), width: 0.3)
),
margin: EdgeInsets.only(bottom: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(15), topRight: Radius.circular(15)),
color: Theme.of(context).primaryColor,
),
padding: EdgeInsets.all(10),
child: Text(
post.title,
textAlign: TextAlign.left,
style: Theme.of(context).textTheme.headline5.copyWith(color: Colors.white),),
),
Container(
child: Text(
post.body,
style: Theme.of(context).textTheme.bodyText2,
),
padding: EdgeInsets.all(10),
),
],
)
);
}
}
post_list_page.dart
:
import 'package:flutter/material.dart';
import '../../controllers/post_controller.dart';
import '../../models/post.dart';
import 'post_list_item.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
class PostListPage extends StatefulWidget {
@override
_PostListPageState createState() => _PostListPageState();
}
// StateMVC
class _PostListPageState extends StateMVC {
//
PostController _controller;
// StateMVC
//
_PostListPageState() : super(PostController()) {
_controller = controller as PostController;
}
//
//
@override
void initState() {
super.initState();
_controller.init();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Post List Page"),
),
body: _buildContent()
);
}
Widget _buildContent() {
//
final state = _controller.currentState;
if (state is PostResultLoading) {
//
return Center(
child: CircularProgressIndicator(),
);
} else if (state is PostResultFailure) {
//
return Center(
child: Text(
state.error,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4.copyWith(color: Colors.red)
),
);
} else {
//
final posts = (state as PostResultSuccess).postList.posts;
return Padding(
padding: EdgeInsets.all(10),
// ListView.builder
//
child: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
//
//
return PostListItem(posts[index]);
},
),
);
}
}
}
.
ネットワークの操作方法を説明的な例で簡単に説明しようとしました。
私の記事があなたに役立つことを願っています)
皆さん良いコードを!