#flutter #flutter-getx
Вопрос:
Проблема, с которой я сталкиваюсь, заключается в том, что текст пользовательского интерфейса не обновляется. Данные, которые я хочу, в данном случае placeName, успешно напечатаны на консоли ОТЛАДКИ, но это не меняет пользовательский интерфейс текстового виджета. Я думал, что при простом управлении операторами в Getx он обновит переменную с помощью update() в методе. Я столкнулся с подобной ситуацией, и я не мог понять этого раньше, поэтому мне пришлось использовать statefuleWidget, чтобы решить ее. Но на этот раз я хотел бы продолжить это с Getx.
введите описание изображения здесь
Кто-нибудь может мне помочь?
2021-11-10 Я обновил свой код, но он по-прежнему не работает
2021-11-18 Я понял это, изменив возвращаемый тип функции (searchCoordinateAddress) и присвоив его переменной (pickUpLocation), которую я хотел обновить.
// home_controller.dart
class HomeController extends GetxController {
...
Rx<Address> pickUpLocation = Address().obs;
RxBool isLoading = false.obs;
...
void locatePosition() async {
...
...
// String? address = await UberRepository.to.searchCoordinateAddress(position); // previous
// current
Address? address = await UberRepository.to.searchCoordinateAddress(position);
pickUpLocation(address);
isLoading(true);
}
// previous
/*
void updatePickUpLocationAddress(Address pickUpAddress) {
print("pickUpAddress.placeName: ${pickUpAddress.placeName}");
pickUpLocation(pickUpAddress);
print("pickUpLocation.value.placeName: ${pickUpLocation.value.placeName}");
}
}
*/
// uber_repository.dart
class UberRepository extends GetConnect {
static UberRepository get to => Get.find();
@override
void onInit() {
httpClient.baseUrl = 'https://maps.googleapis.com/';
super.onInit();
}
// Future<String?> // previous
// current
Future<Address?> searchCoordinateAddress(Position position) async {
String placeAddress = "";
String url =
'maps/api/geocode/json?latlng=${position.latitude},${position.longitude}amp;key=$mapKey';
final response = await get(url);
if (response.status.hasError) {
Future.error(response.statusText!);
} else {
placeAddress = response.body["results"][0]["formatted_address"];
Address userPickUpAddress = Address();
userPickUpAddress.latitude = position.latitude;
userPickUpAddress.longitude = position.longitude;
userPickUpAddress.placeName = placeAddress;
return userPickUpAddress; // current
// HomeController().updatePickUpLocationAddress(userPickUpAddress); // previous
}
// return placeAddress; // previous
}
}
// home.dart
class Home extends GetView<HomeController> {
const Home({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
...
body: Stack(
children: [
GoogleMap(
padding: EdgeInsets.only(
bottom: controller.bottomPaddingOfMap.value,
),
mapType: MapType.normal,
myLocationButtonEnabled: true,
initialCameraPosition: controller.kGooglePlex,
myLocationEnabled: true,
zoomGesturesEnabled: true,
zoomControlsEnabled: true,
onMapCreated: (GoogleMapController googleMapController) {
controller.controllerGoogleMap.complete(googleMapController);
controller.newGoogleMapController = googleMapController;
// when map created and map is set correctly, call current location
controller.setBottomPaddingOfMap();
controller.locatePosition();
},
),
...
...
Expanded(
child: Obx(() =>
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// TODO: UI update...
!controller.isLoading.value
? CircularProgressIndicator()
: Text(
controller.pickUpLocation.value != null
? controller.pickUpLocation.value.placeName!
: "Add Home",
maxLines: 2,
overflow: TextOverflow.ellipsis,
softWrap: false,
),
SizedBox(height: 4.0),
Text(
"Your living home address",
style: TextStyle(
color: Colors.black54,
fontSize: 12.0,
),
),
],
),
),
),
...
// address.dart
class Address {
String? placeFormattedAddress;
String? placeName;
String? placeId;
double? latitude;
double? longitude;
Address({
this.placeFormattedAddress,
this.placeName,
this.placeId,
this.latitude,
this.longitude,
});
}
Ответ №1:
Вы можете сделать это с помощью Obx
. В вашем классе контроллера сделайте что-то вроде этого
class HomeController extends GetxController {
Address get pickupLocation => _pickupLocation.value;
set pickupLocation(Address value) {
_pickupLocation.value = value;
}
Rx<Address> pickUpLocation= Rx<Address>(Address());
...
...
...
void updatePickUpLocationAddress(Address? pickUpAddress) {
pickUpLocation = pickUpAddress;
print("Here? ${pickUpLocation!.placeName!}"); // printed correctly as I intended
}
}
Теперь в вашем классе пользовательского интерфейса используйте Obx вместо GetBuilder следующим образом
// home.dart
class Home extends GetView<HomeController> {
const Home({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
...
...
...
...
Obx(() => controller.pickupLocation.placeName != null
? Text(controller.pickupLocation.placeName)
: Text('Add home')),
...
Комментарии:
1. Я следовал вашему коду, и была ошибка проверки null, и я переместил Obx(() => ) в родительский виджет, и ошибка исчезла, но данные имени места — «, пустая строка. Я думаю, что это не относится к пользовательскому интерфейсу… Что мне делать?
2. Я могу распечатать нужные данные в HomeController, но сторона пользовательского интерфейса не обновляется и показывает («») пустую строку. Итак, я предполагаю, что метод сборки Home возвращает виджеты раньше, чем HomeController, поэтому данные не применяются к пользовательскому интерфейсу. У вас есть какие-либо идеи для этого?
3. Вызовите метод api внутри OnInit() и добавьте флаг, чтобы отслеживать, получен ли ответ, который вы уже получили. Когда вы загружаете состояние, вы можете показать диалоговое окно прогресса, когда pickupLocation обновляется значением api, обновите состояние.
4. Я все еще борюсь с этим вопросом… Я добавил переменную isLoading Rxbool на контроллер, и я закодировал, когда это значение true, показываю имя места, также я проверил, что печать pickUpLocation.value.placeName обновляется раньше, чем isLoading становится true. Но controller.pickUpLocation.value.placeName на стороне пользовательского интерфейса равно нулю. Что мне делать? Это так расстраивает
5. Обновляются ли значения в контроллере?
Ответ №2:
Я думаю, вам нужно вызвать pickUpLocation.refresh()
свой виджет. Вот соответствующая часть из примера со страницы разработки getx https://pub.dev/packages/get:
// `Rx` don't have any clue when you change something inside user.
// So, for custom classes, we need to manually "notify" the change.
user.refresh();
Комментарии:
1. Я добавил pickUpLocation.refresh() в функцию updatePickUpLocationAddress, она не работает, и я использовал метод обновления, как показано ниже: « pickUpLocation.update((value) { значение! .placeName = pickUpAddress.placeName; }); « пользовательский интерфейс по-прежнему не обновляется… Я вижу только, что имя места напечатано правильно… но не на стороне пользовательского интерфейса.