添付のようにURLからアイキャッチ画像とタイトルを取得して表示させる画面を作成しています。
今回の問題点としては、ゴミ箱マークをタップした時にデータから削除され、動的に表示されているリストからも見えないようにリビルドしたいのですが、Providerの使い方を理解できていないようで表示が変わりません・・。
大変恐縮ですが、原因がわかる方がいらっしゃいましたらお力添えいただけませんでしょうか。
main.dart
Dart
1import 'package:flutter/material.dart'; 2import 'cliplist_model.dart'; 3import 'package:url_launcher/url_launcher.dart'; 4import 'package:shared_preferences/shared_preferences.dart'; 5import 'package:provider/provider.dart'; 6 7void main() { 8 runApp( 9 ChangeNotifierProvider<ClipListModel>( 10 create: (context) => ClipListModel(), 11 child:MyApp() 12 )); 13} 14 15class MyApp extends StatelessWidget { 16 // This widget is the root of your application. 17 18 Widget build(BuildContext context) { 19 savedata(); 20 21 return MaterialApp( 22 title: 'Flutter Demo', 23 theme: ThemeData( 24 primarySwatch: Colors.blue, 25 ), 26 home: ClipScreen(), 27 ); 28 } 29} 30class ClipScreen extends StatelessWidget { 31 const ClipScreen({Key key}) : super(key: key); 32 33 34 Widget build(BuildContext context) { 35 return Scaffold( 36 appBar: AppBar( 37 title: Text("クリップリスト"), 38 ), 39 body: Center( 40 child: Container( 41 child: FutureBuilder<List<PageData>>( 42 future: Provider.of<ClipListModel>(context, listen: false).request(), 43 builder: (context, dataSnapshot) { 44 if (dataSnapshot.connectionState == 45 ConnectionState.waiting) { 46 // 非同期処理未完了 = 通信中 47 return Center( 48 child: CircularProgressIndicator(), 49 ); 50 } 51 52 if (dataSnapshot.error != null) { 53 // エラー 54 return Center( 55 child: Text('エラーが発生しました。一度アプリを終了し再度起動してください') 56 ); 57 } 58 59 if (dataSnapshot.data.length == 0) { 60 return Center( 61 child: Text('データがありません') 62 ); 63 } 64 return clipListContents(dataSnapshot.data); 65 }))) 66 ); 67 } 68} 69 70 71 72void savedata()async{ 73 SharedPreferences saveprefs = await SharedPreferences.getInstance(); 74 List<String> tmpData = ["https://qiita.com/","https://tenki.jp/","https://news.yahoo.co.jp/"]; 75 await saveprefs.setStringList("CLIPLIST", tmpData); 76 77} 78 79 80Widget clipListContents(List<PageData> cliplistdata) { 81 return ListView.builder( 82 physics: AlwaysScrollableScrollPhysics(), 83 itemCount: cliplistdata.length, 84 itemBuilder: (lctx, index) => 85 Consumer<ClipListModel>( 86 builder: (context, clipdata, child) { 87 return Padding( 88 padding: const EdgeInsets.only( 89 right: 8.0, left: 8.0), 90 child: InkWell( 91 onTap: () { 92 launch(cliplistdata[index].url); 93 }, 94 child: Row( 95 mainAxisAlignment: MainAxisAlignment 96 .spaceBetween, 97 children: <Widget>[ 98 Image.network( 99 cliplistdata[index].image, 100 height: 100.0, width: 100.0), 101 new Expanded( 102 child: new Column( 103 crossAxisAlignment: 104 CrossAxisAlignment.start, 105 children: <Widget>[ 106 Padding( 107 padding: 108 EdgeInsets.only( 109 left: 8.0), 110 child: Text( 111 (cliplistdata 112 [index] 113 .sitename), 114 style: 115 TextStyle( 116 fontSize: 18)), 117 ), 118 Padding( 119 padding: 120 EdgeInsets.only( 121 left: 12.0), 122 child: Text( 123 cliplistdata 124 [index] 125 .title, 126 style: TextStyle( 127 color: Colors 128 .black38)), 129 ) 130 ])), 131 IconButton( 132 icon: const Icon(Icons.delete), 133 onPressed: () { 134 ClipListModel().trash( 135 cliplistdata[index]); 136 showDialog( 137 context: lctx, 138 builder: (_) { 139 return AlertDialog( 140 content: Text( 141 "クリップリストから削除します"), 142 actions: <Widget>[ 143 FlatButton( 144 onPressed: () => 145 Navigator 146 .of(lctx) 147 .pop //OKボタンをクリックしてもダイアログが閉じないので一旦OKを消している 148 ) 149 ], 150 ); 151 }, 152 ); 153 }, 154 ), 155 ]), 156 ) 157 ); 158 }), 159 ); 160} 161 162
cliplist_model.dart
dart
1import 'package:flutter/material.dart'; 2import 'package:flutter/foundation.dart'; 3import 'package:shared_preferences/shared_preferences.dart'; 4import 'package:universal_html/driver.dart' as driver; 5import 'package:http/http.dart' as http; 6import 'package:html/parser.dart'; 7import 'package:http/http.dart'; 8 9class ClipListModel extends ChangeNotifier { 10 List<String> cliplist = []; 11 List<String> bookmark = []; 12 List<PageData> pagedataList = []; 13 14 Future<List<PageData>> request() async { 15 if (pagedataList != null) { 16 pagedataList.removeRange(0, pagedataList.length); 17 } 18 SharedPreferences prefs = await SharedPreferences.getInstance(); 19 cliplist = prefs.getStringList("CLIPLIST"); 20 if(cliplist==null){ 21 cliplist=[]; 22 } 23 24 for (int i = 0; i < cliplist.length; i++) { 25 PageData tmpPageData = new PageData(); 26 tmpPageData = await fetch(cliplist[i]); 27 pagedataList.add(tmpPageData); 28 } 29 notifyListeners(); 30 return pagedataList; 31 } 32 33 Future<void> trash(deletePageData) async { 34 if(pagedataList!= null){ 35 pagedataList.remove(deletePageData); 36 } 37 38 SharedPreferences prefs = await SharedPreferences.getInstance(); 39 cliplist = prefs.getStringList("CLIPLIST"); 40 cliplist.remove(deletePageData.url); 41 await prefs.setStringList("CLIPLIST", cliplist); 42 43 notifyListeners(); 44 } 45 46 _validateUrl(String url) { 47 if (url?.startsWith('http://') == true || 48 url?.startsWith('https://') == true) { 49 return url; 50 } 51 else { 52 return 'http://$url'; 53 } 54 } 55 56 Future<PageData> fetch(url) async { 57 final client = Client(); 58 final response = await client.get(_validateUrl(url)); 59 final document = parse(response.body); 60 61 PageData tmpPageData = new PageData(); 62 tmpPageData.url = url; 63 64 var elements = document.getElementsByTagName('meta'); 65 //final linkElements = document.getElementsByTagName('link'); 66 67 for (int i = 0; i < elements.length; i++) { 68 if (elements[i].attributes['property'] == 'og:site_name') { 69 tmpPageData.sitename = elements[i].attributes['content']; 70 continue; 71 } 72 if (elements[i].attributes['property'] == 'og:title') { 73 tmpPageData.title = elements[i].attributes['content']; 74 continue; 75 } 76 if (elements[i].attributes['property'] == 'og:image') { 77 tmpPageData.image = elements[i].attributes['content']; 78 continue; 79 } 80 } 81 return tmpPageData; 82 } 83 84} 85 86 87class PageData{ 88 String sitename; 89 String title; 90 String image; 91 String url; 92} 93
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/08/05 06:21