我一直在观看 YouTube 视频并阅读如何使用 GetX 来显示 API 数据,但我无法让它与我的 API 一起使用。我无法弄清楚我缺少什么才能从我的 StockQuoteModel 显示股票价格。我试图将价格放入 ListView 的尾随部分,但不知道如何访问数据。
main.dart
void main() async {
await GetStorage.init();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
主页.dart
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final StockController sC = Get.put(StockController());
final StockQuoteController sQC = Get.put(StockQuoteController());
TextEditingController tEC = TextEditingController();
return Scaffold(
appBar: AppBar(
title: Text('Add to List Practice'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Get.bottomSheet(
Container(
height: 150,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(100, 0, 100, 10),
child: TextField(
controller: tEC,
autofocus: true,
maxLines: 1,
autocorrect: false,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.characters,
decoration: InputDecoration(
labelText: 'Add Stock',
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black87,
),
borderRadius: BorderRadius.circular(10),
),
),
onSubmitted: (text) {
sC.stocks.add(Stock(symbol: tEC.text));
tEC.clear();
Get.back();
},
),
),
// SizedBox(height: 15),
ElevatedButton(
onPressed: () {
sC.stocks.add(Stock(symbol: tEC.text));
tEC.clear();
Get.back();
},
child: Text('Enter'),
style: ElevatedButton.styleFrom(
primary: Colors.blue,
),
),
],
),
),
enableDrag: false,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0)),
),
backgroundColor: Colors.white,
);
},
child: Icon(Icons.add),
),
body: Container(
child: Padding(
padding: EdgeInsets.all(5),
child: Obx(
() => ListView.separated(
itemCount: sC.stocks.length,
separatorBuilder: (context, index) {
return Divider(
color: Colors.black,
thickness: 0.1,
height: 0.0,
);
},
itemBuilder: (context, index) {
return Dismissible(
key: UniqueKey(),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
sC.stocks.removeAt(index);
},
background: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 20.0),
color: Colors.red,
child: Icon(
Icons.delete,
color: Colors.white,
),
),
child: ListTile(
leading: Text(
sC.stocks[index].symbol,
),
trailing: Obx(() {
if (sQC.isLoading.value)
return Text('loading');
else
return Text(
sQC.stockQuote.price); // stuck here!
}),
),
);
},
),
),
),
),
);
}
}
services.dart
class StockQuoteServices {
static Future<StockQuote?> getStockQuote() async {
String url =
'https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=sq&apikey=***********';
http.Response response;
response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
StockQuote stockQuote = StockQuote.fromJson(json.decode(response.body));
return stockQuote;
} else {
return null;
}
}
}
这是 api json
{
"Global Quote": {
"01. symbol": "SQ",
"02. open": "261.8500",
"03. high": "267.7700",
"04. low": "261.2800",
"05. price": "264.0000",
"06. volume": "6374083",
"07. latest trading day": "2021-07-23",
"08. previous close": "260.5900",
"09. change": "3.4100",
"10. change percent": "1.3086%"
}
}
controller.dart
class StockController extends GetxController {
var stocks = [].obs;
void add(Stock s) {
stocks.add(s);
}
@override
void onInit() {
List? storedStocks = GetStorage().read<List>('stocks');
if (storedStocks != null) {
stocks = storedStocks.map((e) => Stock.fromJson(e)).toList().obs;
}
ever(stocks, (_) {
GetStorage().write('stocks', stocks.toList());
});
super.onInit();
}
}
class StockQuoteController extends GetxController {
var isLoading = true.obs;
var stockQuote = StockQuote().obs;
@override
void onInit() {
getStockQuote();
super.onInit();
}
void getStockQuote() async {
try {
isLoading(true);
var quotes = await StockQuoteServices.getStockQuote();
if (quotes != null) {
stockQuote.value = quotes;
}
} finally {
isLoading(false);
}
}
}
stockmodel.dart
class Stock {
String symbol;
Stock({required this.symbol});
factory Stock.fromJson(Map<String, dynamic> json) =>
Stock(symbol: json['symbol']);
Map<String, dynamic> toJson() => {'symbol': symbol};
}
stockquotemodel.dart
class StockQuote {
GlobalQuote? globalQuote;
StockQuote({this.globalQuote});
StockQuote.fromJson(Map<String, dynamic> json) {
globalQuote = json['Global Quote'] != null
? new GlobalQuote.fromJson(json['Global Quote'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.globalQuote != null) {
data['Global Quote'] = this.globalQuote?.toJson();
}
return data;
}
}
class GlobalQuote {
String? symbol;
String? open;
String? high;
String? low;
String? price;
String? volume;
String? latestTradingDay;
String? previousClose;
String? change;
String? changePercent;
GlobalQuote(
{this.symbol,
this.open,
this.high,
this.low,
this.price,
this.volume,
this.latestTradingDay,
this.previousClose,
this.change,
this.changePercent});
GlobalQuote.fromJson(Map<String, dynamic> json) {
symbol = json['01. symbol'];
open = json['02. open'];
high = json['03. high'];
low = json['04. low'];
price = json['05. price'];
volume = json['06. volume'];
latestTradingDay = json['07. latest trading day'];
previousClose = json['08. previous close'];
change = json['09. change'];
changePercent = json['10. change percent'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['01. symbol'] = this.symbol;
data['02. open'] = this.open;
data['03. high'] = this.high;
data['04. low'] = this.low;
data['05. price'] = this.price;
data['06. volume'] = this.volume;
data['07. latest trading day'] = this.latestTradingDay;
data['08. previous close'] = this.previousClose;
data['09. change'] = this.change;
data['10. change percent'] = this.changePercent;
return data;
}
}
答案 0 :(得分:0)
Krish Bhanushali 回答了。
我缺少价值。
sQC.stockQuote.value.globalQuote!.price as String
为我工作。
必须添加空检查和作为空安全的字符串。不确定这是否是最好的方法,但它有效。