草庐IT

android - 如何为 Android 制作自定义地点选择器

coder 2023-12-09 原文

据我所知,Google 不允许开发人员自定义地点选择器布局,

所以我想制作一个如下图所示的地点选择器。

它来自deliveroo app,我使用了map api,但它并不完全像这张照片。

这个选择器就像是定制的地方选择器 api。

这是我的代码:

public class Map extends AppCompatActivity implements OnMapReadyCallback {

private GoogleMap mMap;
private LatLng markerLatLong;
private static final int REQUEST_CODE_LOCATION_ENABLE = 1;
private static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 2;
private static String TAG = Map.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.map);
    setToolbar();
    setFragment();
}

public void setFragment() {
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

public void setToolbar() {

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    if (getSupportActionBar() != null) {
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }
    onSearchPlacesClicked(toolbar);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_LOCATION_ENABLE) {
        if (resultCode == RESULT_OK) {
            Log.e(TAG, "location enabled");
            setLocation();
        }
    }else if (requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                Place place = PlaceAutocomplete.getPlace(this, data);
                Log.e(TAG, "Place: " + place.getName());
                setPlace(place.getLatLng());

            } else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
                Status status = PlaceAutocomplete.getStatus(this, data);
                // TODO: Handle the error.
                Log.i(TAG, status.getStatusMessage());

            } else if (resultCode == RESULT_CANCELED) {
                // The user canceled the operation.
            }
        }
}


/**
 * Manipulates the map once available.
 * This callback is triggered when the map is ready to be used.
 * This is where we can add markers or lines, add listeners or move the camera. In this case,
 * we just add a marker near Sydney, Australia.
 * If Google Play services is not installed on the device, the user will be prompted to install
 * it inside the SupportMapFragment. This method will only be triggered once the user has
 * installed Google Play services and returned to the app.
 */
@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
    mMap.setMyLocationEnabled(true);
    mMap.getUiSettings().setMyLocationButtonEnabled(true);
    mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
        @Override
        public void onMapClick(LatLng latLng) {
            setPlace(latLng);
        }
    });
    Button b = (Button) findViewById(R.id.pick_place);
    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (markerLatLong != null) {
                addAddressToPref(-1, markerLatLong.latitude, markerLatLong.longitude);
                startActivity(new Intent(Map.this, StoreList.class));
                Map.this.finish();
            } else {
                Toast.makeText(Map.this, R.string.no_place_selected, Toast.LENGTH_SHORT).show();
            }
        }
    });
    setLocation();

}

public void addAddressToPref(long id, double latitude, double longitude) {
    Singleton.getInstance().setAddressPref(id, latitude, longitude);
}

public void setPlace(final LatLng latLng) {

    mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {

        @Override
        public void onCameraChange(CameraPosition arg0) {
          mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));

            // Remove listener to prevent position reset on camera move.
            mMap.setOnCameraChangeListener(null);
        }
    });
    markerLatLong = latLng;
    mMap.clear();
    mMap.addMarker(new MarkerOptions().position(latLng).title(getString(R.string.my_location)));



}

public void setLocation() {
    AppLocationService gps = new AppLocationService(this);

    // check if GPS enabled
    if (gps.canGetLocation()) {

        double latitude = gps.getLatitude();
        double longitude = gps.getLongitude();

        getLocation(latitude, longitude);
        // \n is for new line
    } else {
        // can't get location
        // GPS or Network is not enabled
        // Ask user to enable GPS/network in settings
        buildAlertMessageNoGps();
    }
}

public void getLocation(double latitude, double longitude) {
    final CoordinatorLayout rootLayout = (CoordinatorLayout) findViewById(R.id.root_view);
    if (latitude != 0 && longitude != 0) {
        LatLng latLng = new LatLng(latitude, longitude);
        CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 15);
        mMap.animateCamera(cameraUpdate);
    } else {
        Snackbar.make(rootLayout, getResources().getString(R.string.location_problem),
                Snackbar.LENGTH_INDEFINITE).setAction("سعی دوباره", new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                setLocation();
            }
        }).show();
    }
}

private void buildAlertMessageNoGps() {
    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage(getString(R.string.turn_on_location_text))
            .setCancelable(false)
            .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
                public void onClick(final DialogInterface dialog, final int id) {
                    Intent intent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    startActivityForResult(intent, REQUEST_CODE_LOCATION_ENABLE);
                }
            })
            .setNegativeButton(getString(R.string.exit), new DialogInterface.OnClickListener() {
                public void onClick(final DialogInterface dialog, final int id) {
                    dialog.cancel();
                    Map.this.finish();
                }
            });
    final AlertDialog alert = builder.create();
    alert.show();

}

public void onSearchPlacesClicked(Toolbar toolbar) {
    ImageView searchPlace = (ImageView) toolbar.findViewById(R.id.search_place);
    searchPlace.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            autoCompleteMethod();
        }
    });
}

public void autoCompleteMethod() {
    try {
        Intent intent =
                new PlaceAutocomplete.IntentBuilder(PlaceAutocomplete.MODE_OVERLAY)
                        .build(this);
        startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);
    } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException e) {
        // TODO: Handle the error.
    }
}

@Override
protected void onResume() {
    super.onResume();
    if (mMap != null) {
        setLocation();
    }
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            break;
    }
    return true;
}

@Override
public void onBackPressed() {
    startActivity(new Intent(Map.this, StoreList.class));
    Map.this.finish();
}
}

最佳答案

为 map 创建 Activity 并在您想要定位的地方调用它:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".Activity.InsertMapsActivity">

<Button
    android:layout_width="wrap_content"
    android:id="@+id/btn_set_garage_location"
    android:text="set location"
    android:layout_height="wrap_content"/>
<fragment
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

java代码:

public class InsertMapsActivity extends FragmentActivity implements LocationListener
{

private GoogleMap googleMap;
private LatLng garageLocation;
Button btnSetGarageLocation;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_insert_maps);
    btnSetGarageLocation = (Button) findViewById(R.id.btn_set_garage_location);
    int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.

    if (status != ConnectionResult.SUCCESS)
    { // Google Play Services are not available

        int requestCode = 10;
        Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode);
        dialog.show();

    }
    else
    { // Google Play Services are available

        // Getting reference to the SupportMapFragment of activity_main.xml
        SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);

        // Getting GoogleMap object from the fragment
        googleMap = fm.getMap();

        // Enabling MyLocation Layer of Google Map
        googleMap.setMyLocationEnabled(true);

        // Getting LocationManager object from System Service LOCATION_SERVICE
        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

        // Creating a criteria object to retrieve provider
        Criteria criteria = new Criteria();

        // Getting the name of the best provider
        String provider = locationManager.getBestProvider(criteria, true);

        // Getting Current Location
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
        {
            // TODO: Consider calling

            return;
        }
        Location location = locationManager.getLastKnownLocation(provider);

        if(location!=null){
            onLocationChanged(location);
        }
        locationManager.requestLocationUpdates(provider, 100, 0, this);

        btnSetGarageLocation.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent intent = getIntent();
                intent.putExtra("location_lat",garageLocation.latitude);
                intent.putExtra("location_lng",garageLocation.longitude);
                setResult(RESULT_OK,intent);
                finish();
            }
        });
    }

    googleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener()
    {
        @Override
        public void onMapClick(LatLng latLng)
        {
            googleMap.clear();
            googleMap.addMarker(new MarkerOptions().position(latLng).title("Custom location").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)));
            garageLocation = latLng;
        }
    });


}

@Override
public void onLocationChanged(Location location)
{

    // Getting latitude of the current location
    double latitude = location.getLatitude();

    // Getting longitude of the current location
    double longitude = location.getLongitude();

    // Creating a LatLng object for the current location
    LatLng latLng = new LatLng(latitude, longitude);

    // Showing the current location in Google Map
    googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));

    // Zoom in the Google Map
    googleMap.animateCamera(CameraUpdateFactory.zoomTo(15));

    googleMap.getMaxZoomLevel();

    // Setting latitude and longitude in the TextView tv_location

}

@Override
public void onStatusChanged(String provider, int status, Bundle extras)
{

}

@Override
public void onProviderEnabled(String provider)
{

}

@Override
public void onProviderDisabled(String provider)
{

}
}

Activity 中:

private int MAP = 2;

Intent intent = new Intent(getApplicationContext(),InsertMapsActivity.class);
                startActivityForResult(intent, MAP);

您的 Activity 结束:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);

    ImageView garageImage = new ImageView(this);
    if (resultCode == Activity.RESULT_OK)
    {

    }

    if(requestCode == MAP)
    {
        double lat = (double) data.getExtras().get("location_lat");
        double lng = (double) data.getExtras().get("location_lng");


    }
}

关于android - 如何为 Android 制作自定义地点选择器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36449891/

有关android - 如何为 Android 制作自定义地点选择器的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  3. ruby - 如何为 emacs 安装 ruby​​-mode - 2

    我刚刚为fedora安装了emacs。我想用emacs编写ruby。为ruby​​提供代码提示、代码完成类型功能所需的工具、扩展是什么? 最佳答案 ruby-mode已经包含在Emacs23之后的版本中。不过,它也可以通过ELPA获得。您可能感兴趣的其他一些事情是集成RVM、feature-mode(Cucumber)、rspec-mode、ruby-electric、inf-ruby、rinari(用于Rails)等。这是我当前用于Ruby开发的Emacs配置:https://github.com/citizen428/emacs

  4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  5. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  6. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  7. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  8. ruby - 如何在 Grape 中定义哈希数组? - 2

    我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>

  9. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  10. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

随机推荐