2017-08-17 153 views
-1

我想添加一個自動完成服務到我的自定義搜索欄(我正在使用一個條目)Xamarin形式爲我的Xamarin形式地圖,但我一直無法這樣做。Xamarin谷歌地圖自動完成

我已經試過用XLabs,但沒有工作,至今我還沒有找到任何其他解決方案。

Xamarin.FormsMaps是否包含任何自動完成功能?或者Xamarin上是否有任何自動完成功能可能會丟失? 你推薦我什麼?如果您需要任何代碼或其他任何內容,請告訴我。

+0

[Xamarin.Forms中的Google Place Autocomplete]可能的重複(https://stackoverflow.com/questions/34390423/google-place-autocomplete-in-xamarin-forms) – hvaughan3

+0

@ hvaughan3我已經看到了一個,但它是一個獨家的android,這就是爲什麼沒有答案在這個問題上檢查。感謝壽。 –

回答

1

這是一個很長的,但在這裏....很明顯,你會想把服務調用代碼class和所有其他代碼ViewModel。您也可能想要在服務調用方法中或周圍添加更多的空值和錯誤檢查。

我遺漏的一個重要部分是Google的要求,即在執行搜索時顯示Google徽標。因此請下載their icon並將其添加到用戶界面。我只在用戶關注Entry時才顯示它。

所以這些都是地方的模型和我自己的Address型號:

public class AddressInfo { 

    public string Address { get; set; } 

    public string City { get; set; } 

    public string State { get; set; } 

    public string ZipCode { get; set; } 

    public double Longitude { get; set; } 

    public double Latitude { get; set; } 
} 

public class PlacesMatchedSubstring { 

    [Newtonsoft.Json.JsonProperty("length")] 
    public int Length { get; set; } 

    [Newtonsoft.Json.JsonProperty("offset")] 
    public int Offset { get; set; } 
} 

public class PlacesTerm { 

    [Newtonsoft.Json.JsonProperty("offset")] 
    public int Offset { get; set; } 

    [Newtonsoft.Json.JsonProperty("value")] 
    public string Value { get; set; } 
} 

public class Prediction { 

    [Newtonsoft.Json.JsonProperty("id")] 
    public string Id { get; set; } 

    [Newtonsoft.Json.JsonProperty("description")] 
    public string Description { get; set; } 

    [Newtonsoft.Json.JsonProperty("matched_substrings")] 
    public List<PlacesMatchedSubstring> MatchedSubstrings { get; set; } 

    [Newtonsoft.Json.JsonProperty("place_id")] 
    public string PlaceId { get; set; } 

    [Newtonsoft.Json.JsonProperty("reference")] 
    public string Reference { get; set; } 

    [Newtonsoft.Json.JsonProperty("terms")] 
    public List<PlacesTerm> Terms { get; set; } 

    [Newtonsoft.Json.JsonProperty("types")] 
    public List<string> Types { get; set; } 
} 

public class PlacesLocationPredictions { 

    [Newtonsoft.Json.JsonProperty("predictions")] 
    public List<Prediction> Predictions { get; set; } 

    [Newtonsoft.Json.JsonProperty("status")] 
    public string Status { get; set; } 
} 

這裏我們所說的地方API:

public const string GooglePlacesApiAutoCompletePath = "https://maps.googleapis.com/maps/api/place/autocomplete/json?key={0}&input={1}&components=country:us"; //Adding country:us limits results to us 

public const string GooglePlacesApiKey = "bTafrOPmO4LpPgAl34r5wQ6LFRWhgTxBW80-3GK"; 

private static HttpClient _httpClientInstance; 
public static HttpClient HttpClientInstance => _httpClientInstance ?? (_httpClientInstance = new HttpClient()); 

private ObservableCollection<AddressInfo> _addresses; 
public ObservableCollection<AddressInfo> Addresses { 
    get => _addresses ?? (_addresses = new ObservableCollection<AddressInfo>()); 
    set { 
     if(_addresses != value) { 
      _addresses = value; 
      OnPropertyChanged(); 
     } 
    }; 
} 

private string _addressText; 
public string AddressText { 
    get => _addressText; 
    set { 
     if(_addressText != value) { 
      _addressText = value; 
      OnPropertyChanged(); 
     } 
    }; 
} 

public async Task GetPlacesPredictionsAsync() { 

    // TODO: Add throttle logic, Google begins denying requests if too many are made in a short amount of time 

    CancellationToken cancellationToken = new CancellationTokenSource(TimeSpan.FromMinutes(2)).Token; 

    using(HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format(GooglePlacesApiAutoCompletePath, ConstantKeys.GooglePlacesApiKey, WebUtility.UrlEncode(_addressText)))) { //Be sure to UrlEncode the search term they enter 

     using(HttpResponseMessage message = await HttpClientInstance.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false)) { 
      if(message.IsSuccessStatusCode) { 
       string json = await message.Content.ReadAsStringAsync().ConfigureAwait(false); 

       PlacesLocationPredictions predictionList = await Task.Run(() => JsonConvert.DeserializeObject<PlacesLocationPredictions>(json)).ConfigureAwait(false); 

       if(predictionList.Status == "OK") { 

        Addresses.Clear(); 

        if(predictionList.Predictions.Count > 0) { 
         foreach(Prediction prediction in predictionList.Predictions) { 
          Addresses.Add(new AddressInfo { 
           Address = prediction.Description 
          }); 
         } 
        } 
       } else { 
        throw new Exception(predictionList.Status); 
       } 
      } 
     } 
    } 
} 

現在的UI ...

<Entry Text="{Binding AddressText}" 
      TextChanged="OnTextChanged" /> 

    <ListView ItemsSource="{Binding Addresses}"> 
     <ListView.ItemTemplate> 
     <DataTemplate> 
      <TextCell Text="{Binding Address}"/> 
     </DataTemplate>Text 
     </ListView.ItemTemplate> 
    </ListView> 

及後面的代碼:

private async void OnTextChanged(object sender, EventArgs eventArgs) { 
    if(!string.IsNullOrWhiteSpace(ViewModel.AddressText)) { 
     await ViewModel.GetPlacesPredictionsAsync(); 
    } 
} 
+0

這正是我所需要的,如果我可以問,你如何獲得座標?你使用地理編碼器? –

+0

@MauricioCárdenas來自'Prediction'類的座標?如果是這樣,是的。我使用Google Geocode API。幾乎相同的代碼,除了我使用服務調用的地理編碼網址,我反序列化到不同的模型的響應。 – hvaughan3

+0

@ hvaughan3 is this line:await ViewModel.GetAddressCoordinatesAsync();應該調用GetPlacesPredictionsAsync? –