Фрагмент автозаполнения в Android Place: невозможно установить текст
Google недавно обновил свой Places SDK для Android, поэтому теперь я тоже обновляю свой код. Я пытаюсь использовать AutocompleteSupportFragment
чтобы позволить пользователю установить свой адрес.
Это мой код:
mAddressEditText = (AutocompleteSupportFragment) getSupportFragmentManager().findFragmentById(R.id.address);
mAddressEditText.setPlaceFields(Arrays.asList(Place.Field.ADDRESS, Place.Field.LAT_LNG));
mAddressEditText.setHint("Address");
mAddressEditText.setText("Test1"); // Works fine at the beginning, disappears after selecting a place and shows only the hint
mAddressEditText.setOnPlaceSelectedListener(new PlaceSelectionListener() {
@Override
public void onPlaceSelected(Place place) {
Log.d(TAG, "Place Selected");
// Other Stuff
mAddressEditText.setText("Test2"); // Doesn't Work, all I can see is the hint
mAddressEditText.setText(place.getAddress()); // Doesn't Work, all I can see is the hint
}
@Override
public void onError(Status status) {
Log.e(TAG, "An error occurred: " + status);
invalidAddressDialog.show();
}
});
В предыдущем SDK фрагмент автоматически устанавливал текст на выбранный адрес. Это не работает в новом SDK (не уверен, намеренно это или нет). Поэтому я пытаюсь установить его вручную. Как вы можете видеть в комментариях в моем коде, используя setText
отлично работает вне слушателей. Внутри слушателя нет.
Я что-то не так делаю или это ошибка?
10 ответов
setText создает для меня ту же проблему - я думаю, что это ошибка. Однако я нашел немного работы с подсказкой. В вашем onPlaceSelected вы можете поставить следующее:
Джава
EditText etPlace = (EditText) autocompleteFragment.getView().findViewById(R.id.places_autocomplete_search_input);
etPlace.setHint(place.getAddress())
Котлин
val etPlace = autocompleteFragment.view?.findViewById(R.id.places_autocomplete_search_input) as EditText
etPlace.hint = place.address
Это код, который я использую, и он работает отлично.
Внесите некоторые изменения в build.gradle (уровень приложения)
Добавьте это в build.gradle:
android{
...
ext {
googlePlayServicesVersion = "15.0.1"
}
}
Добавьте эти зависимости:
dependencies {
...
//Also if you're using any firebase dependencies make sure that the are up to date
implementation 'com.google.android.gms:play-services-places:16.0.0'
implementation 'com.google.android.libraries.places:places:1.1.0'
}
apply plugin: 'com.google.gms.google-services'
В формате XML:
<fragment
android:id="@+id/autocomplete_fragment"
android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Код в Activity:
private void initGooglePlacesApi() {
// Initialize Places.
Places.initialize(getApplicationContext(), "YOUR_API_KEY");
// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(getApplicationContext());
// Initialize the AutocompleteSupportFragment.
AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);
autocompleteFragment.setHint(getString(R.string.select_location_search_bar));
// autocompleteFragment.setLocationRestriction(RectangularBounds.newInstance(
// new LatLng(34.7006096, 19.2477876),
// new LatLng(41.7488862, 29.7296986))); //Greece bounds
autocompleteFragment.setCountry("gr");
// Specify the types of place data to return.
autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ADDRESS, Place.Field.ADDRESS_COMPONENTS));
autocompleteFragment.setTypeFilter(TypeFilter.ADDRESS);
// Set up a PlaceSelectionListener to handle the response.
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
@Override
public void onPlaceSelected(Place place) {
if(place.getAddressComponents().asList().get(0).getTypes().get(0).equalsIgnoreCase("route")){
binding.textViewLocation.setText(place.getAddress()); //Works well
location = place.getAddress();
}else{ //If user does not choose a specific place.
AndroidUtils.vibratePhone(getApplication(), 200);
TastyToast.makeText(getApplicationContext(),
getString(R.string.choose_an_address), TastyToast.DEFAULT, TastyToast.CONFUSING);
}
Log.i(TAG, "Place: " + place.getAddressComponents().asList().get(0).getTypes().get(0) + ", " + place.getId() + ", " + place.getAddress());
}
@Override
public void onError(Status status) {
Log.i(TAG, "An error occurred: " + status);
}
});
}
Я нашел довольно простое решение... просто немного задержите момент, когда вы устанавливаете текст в EditText. Итак, в вашем PlaceSelectionListener просто сделайте это следующим образом:
Handler().postDelayed({
mAddressEditText.setText(place.getAddress());
}, 300)
PS: это код kotlin, но он почти похож на Java
Установив «NAME» в setPlaceFields, выбранный адрес автоматически отображается во фрагменте:
AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);
// Set "Place.Field.NAME" as below here to show the selected item //
autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, **Place.Field.NAME**,Place.Field.ADDRESS,Place.Field.LAT_LNG));
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
@Override
public void onPlaceSelected(@NonNull Place place) {
// TODO: Get info about the selected place. }
@Override
public void onError(@NonNull Status status) {
// TODO: Handle the error. }
});
Решение от Матиаса работает, но находится в котлине. Ниже представлена такая же реализация на Java.
@Override
public void onPlaceSelected(Place place) {
String name = place.getName()+", "+place.getAddress();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
autocompleteFragmentDestination.setText(name);
}
},300);
}
РЕДАКТИРОВАТЬ: вот мой обновленный ответ
# When you are using AutocompleteSupportFragment or AutocompleteActivity
# in Fragments, do this:
public class YourFragment extends Fragment {
/.../
@Override
public void onActivityResult (int requestCode,int resultCode,
@Nullable Intent data){
# AUTOCOMPLETE_REQUEST_CODE is just a unique constant, define it
if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
if (resultCode == AutocompleteActivity.RESULT_OK) {
Place place = Autocomplete.getPlaceFromIntent(data);
// when resultcode is RESULT_OK
mAddressEditText.setText(place.getName());
// Notice this line, update your editText up here
}else if (resultCode == AutocompleteActivity.RESULT_ERROR) {
Status status = Autocomplete.getStatusFromIntent(data);
// Handle error
} else if (resultCode == AutocompleteActivity.RESULT_CANCELED) {
// Handle results if canceled
}
super.onActivityResult(requestCode, resultCode, data);
}
}
/.../
}
# If you are extending AppCompatActivity, you might want to do this
# ONLY when you are already doing something in onActivityResult
public class YourActivity extends AppCompatActivity{
/.../
@Override
public void onActivityResult (int requestCode,int resultCode,@Nullable Intent data){
# your logic here.
/.../
# if you are already overriding onActivityResult,
# do not forget to put this line
super.onActivityResult(requestCode, resultCode, data);
}
/.../
}
У меня тоже была проблема. Оказывается, вы должны переопределить это и реализовать его в любом случае, будь то с помощью AutocompleteSupportFragment
или же AutocompleteActivity
если вы работаете во фрагментах.
Если вы используете AppCompatActivity
вам не нужно это реализовывать, но если вы уже переигрываете onActivityResult
чтобы что-то сделать, не забудьте вызвать базовый метод super.onActivityResult
Простой. Используйте Spannable строку, чтобы установить цвет!
val autocompleteFragment = childFragmentManager.findFragmentById(R.id.location_filter_autocomplete) as AutocompleteSupportFragment
val text = SpannableString("Enter a location")
text.setSpan(ForegroundColorSpan(Color.BLACK), 0, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
autocompleteFragment.setHint(text)
Сделайте то же самое внутри onPlaceSelectedListener()
Я считаю, что это ошибка, потому что не имеет смысла так работать. То, что работает, это установить другие тексты автозаполнения, но не свой собственный. Это должно быть ошибкой.
Я попробовал решение CacheMeOutside, но оно вообще не сработало. Итак, я решил попробовать решение Матиаса, и оно сработало, потому что текст фактически устанавливается, а затем по какой-то причине сразу же удаляется. Небольшая задержка исправляет. Задержка может составлять всего 1 миллисекунду.
Если мое решение вам не подходит, вы можете попробовать поэкспериментировать с задержкой. Также кажется, что он не останавливает рендеринг представления, поэтому вы можете установить любое время, когда захотите.
private lateinit var autocomplete: AutocompleteSupportFragment
override fun onPlaceSelected(place: Place) {
Timer("SetAddress", false).schedule(1) {
autocomplete.setText(place.address)
}
}
Фрагмент кода на Kotlin. Если ваш код написан на Java, просто найдите какой-нибудь инструмент, чтобы отложить выполнение кода на некоторое время.
Получить ссылку на AutoCompleteFragment, а затем установить текст для фрагмента автозаполнения, например
autoCompleteFragment.setText("Address")
для справки вы можете посмотреть документацию