Android之仿ele地图定位效果

PS:最近项目要求,希望在选择地址的时候能够仿ele来实现定位效果.因此就去做了一下.不过ele使用高德地图实现的,我是用百度地图实现的.没办法,公司说用百度那就用百度的吧.个人觉得高德应该更加的精准.但也无所谓反正都是地图定位+Poi搜索.都差不多.

 

1.使用LocationClient核心类实现定位

2.使用GeoCoder实现地理编码和反地理编码

3.使用PoiSearch实现相关的Poi搜索

4.使用SuggestionSearch实现在线建议查询

5.ele定位效果的实现

  百度地图定位的相关流程我就不进行介绍了.以前也写过流程,至于如何创建应用,如何申请什么的,我就不进行介绍了,官方上有关于如何创建应用申请AK的流程,还是非常的详细的.还是说一下如何实现ele的定位效果吧,可能最后的效果稍微有些偏差,不过大体还是差不多的,主要还是提供一个思路.

1.LocationClient定位核心类

  LocationClient是实现地图定位的核心类,LBS基站定位就是通过使用LocationClient来实现的,具体的使用方式如下:

 /**
   * 设置定位的option
   * */
mLocClient = new LocationClient(this);  //实例化LocationClient
mLocClient.registerLocationListener(new MyLocationListener()); //注册定位监听
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true);            // 打开gps
option.setCoorType("bd09ll");       // 设置坐标类型
option.setScanSpan(1000);           // 设置查询范围,默认500
mLocClient.setLocOption(option);    // 设置option
mLocClient.start();

LocationClient实例化之后,需要设置相应的LocationOption,也就是定位的一些选项,通过指定的设置,决定以怎样的形式实现定位,比如说定位的时候需要打开gps,设置坐标的类型,以及搜索的范围等等.同时需要设置相关的监听.

/**
     * LBS定位监听
     * */
    public class MyLocationListener implements BDLocationListener {

        @Override
        public void onReceiveLocation(BDLocation location) {
            // map view 销毁后不在处理新接收的位置

            if (IsFirstLoc) {
                IsFirstLoc = false;
                point = new LatLng(location.getLatitude(), location.getLongitude());
                geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(point));

                /**
                 * 设置当前位置为定位到的地理位置
                 * */
                MapStatus.Builder builder = new MapStatus.Builder();
                builder.target(point).zoom(20.0f);
                baiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
            }
        }
    }

设置完相关的监听之后就可以在LocationClient完成定位后去做一些其他的事情,比如说在地图上显示定位到的当前位置,获取到定位的坐标,坐标的形式是以经度和纬度的组合形式,获取到定位到的坐标后,我们就可以根据坐标实现地理编码和反地理编码.

2.使用GeoCoder实现地理编码与反编码

 GeoCoder的使用方式还是非常简单的,只需要实例化对象,然后设置监听回调就可以了..

 地理编码:将当前的位置信息转化成坐标的形式(经度+纬度)

geoCoder = GeoCoder.newInstance(); //GeoCoder对象的实例化
geoCoder.setOnGetGeoCodeResultListener(this); //设置监听
//需要实现的方法:
@Override
public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
    //这里一般不做其他处理
}

反地理编码:将我们当前的坐标信息转化成物理位置.需要额外注意:反地理编码需要在网络状态连接良好的情况下才能够实现

geoCoder = GeoCoder.newInstance(); //GeoCoder对象的实例化
geoCoder.setOnGetGeoCodeResultListener(this); //设置监听
//需要实现的方法:
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
    /**
      * 获取反地理编码后的城市信息,街道信息,Poi信息等
      * */
    currentCity = reverseGeoCodeResult.getAddress();
}
ReverseGeoCodeResult类的具体形式
package com.baidu.mapapi.search.geocode;

import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable.Creator;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.search.core.PoiInfo;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.core.SearchResult.ERRORNO;
import com.baidu.mapapi.search.geocode.c;
import com.baidu.mapapi.search.geocode.d;
import java.util.List;

public class ReverseGeoCodeResult extends SearchResult {
    private String a;
    private String b;
    private ReverseGeoCodeResult.AddressComponent c;
    private LatLng d;
    private List<PoiInfo> e;
    public static final Creator<ReverseGeoCodeResult> CREATOR = new c();

    ReverseGeoCodeResult() {
    }

    ReverseGeoCodeResult(ERRORNO var1) {
        super(var1);
    }

    protected ReverseGeoCodeResult(Parcel var1) {
        super(var1);
        this.a = var1.readString();
        this.b = var1.readString();
        this.c = (ReverseGeoCodeResult.AddressComponent)var1.readParcelable(ReverseGeoCodeResult.AddressComponent.class.getClassLoader());
        this.d = (LatLng)var1.readValue(LatLng.class.getClassLoader());
        this.e = var1.createTypedArrayList(PoiInfo.CREATOR);
    }

    public String getBusinessCircle() {
        return this.a;
    }

    void a(String var1) {
        this.a = var1;
    }

    public String getAddress() {
        return this.b;
    }

    void b(String var1) {
        this.b = var1;
    }

    public ReverseGeoCodeResult.AddressComponent getAddressDetail() {
        return this.c;
    }

    void a(ReverseGeoCodeResult.AddressComponent var1) {
        this.c = var1;
    }

    public LatLng getLocation() {
        return this.d;
    }

    void a(LatLng var1) {
        this.d = var1;
    }

    public List<PoiInfo> getPoiList() {
        return this.e;
    }

    void a(List<PoiInfo> var1) {
        this.e = var1;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel var1, int var2) {
        super.writeToParcel(var1, var2);
        var1.writeString(this.a);
        var1.writeString(this.b);
        var1.writeParcelable(this.c, 0);
        var1.writeValue(this.d);
        var1.writeTypedList(this.e);
    }

    public static class AddressComponent implements Parcelable {
        public String streetNumber;
        public String street;
        public String district;
        public String city;
        public String province;
        public static final Creator<ReverseGeoCodeResult.AddressComponent> CREATOR = new d();

        public int describeContents() {
            return 0;
        }

        public void writeToParcel(Parcel var1, int var2) {
            var1.writeString(this.streetNumber);
            var1.writeString(this.street);
            var1.writeString(this.district);
            var1.writeString(this.city);
            var1.writeString(this.province);
        }

        public AddressComponent() {
        }

        protected AddressComponent(Parcel var1) {
            this.streetNumber = var1.readString();
            this.street = var1.readString();
            this.district = var1.readString();
            this.city = var1.readString();
            this.province = var1.readString();
        }
    }
}

  反地理编码结束之后,我们就可以拿到一些相关信息,比如说我们当前位置所在的省市,城市,区域,街道,以及街道号,以及附近的一些Poi等等.这些都可以通过反地理编码的结束后的回调拿到相关的信息.这里我们的反地理编码只是获取了相关的城市信息.为了后续的在线建议查询做准备.

3.使用PoiSearch实现相关的Poi搜索

  Poi:poi中文翻译为兴趣点.其实就是周边的一些ktv,酒店,餐馆,理发店等等都是一个poi.在实现了基础定位的前提后,去搜索附近的poi.这样就可以完成一些其他事情.比如说订一份外卖,预定一个房间等等.这些都是基于poi搜索才能够实现的.

  Poi搜索有三种不同的方式,周边搜索,区域搜索,城市内搜索.这里我只说周边搜索,因为ele应该也是使用的周边搜索.

  三种搜索方式代码上其实大体相同,只是搜索的方式不大一样而已.大体分为三个步骤,首先是对象的实例化,然后设置PoiNearBySearchOption,最后设置监听回调即可.

/**
     * 房子Poi数据搜索
     * @注意: 所有的Poi搜索都是异步完成的
     * */
    private void nearByAllPoiSearch() {
        allpoiSearch = PoiSearch.newInstance();
        allPoiData.clear();
        allpoiSearch.setOnGetPoiSearchResultListener(new OnGetPoiSearchResultListener() {
            @Override
            public void onGetPoiResult(PoiResult poiResult) {
                if (poiResult.getAllPoi() == null) {
                    Toast.makeText(getApplicationContext(),"定位失败,暂无数据信息",Toast.LENGTH_LONG).show();
                } else {
                    allPoiData.addAll(poiResult.getAllPoi());
                }
            }

            @Override
            public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {
                //Poi详情数据
            }

            @Override
            public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {
                //室内Poi数据
            }
        });

        /**
         * 设置Poi Option
         * 当前搜索为附近搜索:以圆形的状态进行搜索
         * 还有两种其他的搜素方式:范围搜素和城市内搜索
         * */
        PoiNearbySearchOption nearbySearchOption = new PoiNearbySearchOption();
        nearbySearchOption.location(new LatLng(point.latitude, point.longitude)); //设置坐标
        nearbySearchOption.keyword("房子");                                       //设置关键字
        nearbySearchOption.radius(2000);                                          //搜索范围的半径
        nearbySearchOption.pageCapacity(15);                                      //设置最多允许加载的poi数量,默认10
        allpoiSearch.searchNearby(nearbySearchOption);
    }

这里我设置了Poi允许加载的数量,默认是10条数据,也就是说,如果我们不设置分页,百度只会给我们返回10条Poi数据信息,这是默认的情况,这里我修改了允许加载的Poi数量,也就是15个Poi数据信息,如果大家不想写分页,那么可以设置这个属性,按照自己的方式去指定加载多少条数据.

4.使用SuggestionSearch实现在线建议查询

  在线建议查询:根据城市和关键字搜索出相应的位置信息(模糊查询)使用起来还是非常的简单的.只需要实例化对象,设置结果回调就可以根据我们输入的关键字搜索相关的地理位置信息.

/**
             * 在线建议查询对象实例化+设置监听
             * @在线建议查询: 根据城市和关键字搜索出相应的位置信息(模糊查询)
             * */
            keyWordsPoiSearch = SuggestionSearch.newInstance();
            keyWordsPoiSearch.setOnGetSuggestionResultListener(new OnGetSuggestionResultListener() {
                @Override
                public void onGetSuggestionResult(SuggestionResult suggestionResult) {
                    keyWordPoiData.clear();
                    if (suggestionResult.getAllSuggestions() == null) {
                        Toast.makeText(getApplicationContext(),"暂无数据信息",Toast.LENGTH_LONG).show();
                    } else {
                        keyWordPoiData = suggestionResult.getAllSuggestions();
                        //设置Adapter结束
                        suggestAdapter = new SuggestAddressAdapter(getApplicationContext(), keyWordPoiData);
                        inputPoiListView.setAdapter(suggestAdapter);
                    }
                }
            });
            keyWordsPoiSearch.requestSuggestion((new SuggestionSearchOption()).keyword(location_name.getText().toString()).city(currentCity));

大体的东西基本就介绍完了.还是来分析一下ele是如何实现的定位效果吧.我是按照我的思路去实现的,可能会有一些与其并不是特别的一样.总之还是提供一个大体的思路才是关键.我们先看一下效果图

  我们看着这个效果图来说,上层是一个搜索框和一个MapView.并且中间位置有一个ImageView.下层是一个ViewIndicator,我这个ViewIndicator并没有自定义View,只是一个布局,因此实现起来可能没有那么的优雅,大家可以选择去优化这里,然后下面是一个ViewPager来实现4个Fragment的切换.

  需要说明的就是中间这个ImageView,我在这里标识了它并不是地图上的Marker.而是直接定义了一个FrameLayout,让这个ImageView粘在了这个中间位置,我们在移动地图的时候,我们看着好像是这个ImageView也在移动,其实只是这个MapView在移动而已,这个ImageView实际是一直保持不动的.那么移动的时候我们明显看到数据发生了变化,这里只是每次在移动的时候都获取MapView的中心点坐标,因为ImageView是始终在中心显示的,因此每次取得就是中心坐标,然后再进行Poi搜素就可以了.这样就可以发现Fragment里的数据会发生明显的变化.

  这里我第一次定位和Poi搜索都是在MainActivity里面完成的,然后将数据通过setArguments()传递过去.Fragment在首次加载的时候只需要getArguments()来获取相应的数据,然后在自己的ListView当中设置adapter就可以第一次直接显示数据了,同时Fragment在onAttach到Activity的时候需要注册一个广播,这个广播的用来接收,当地图状态发生改变的时候,也就是我们平移了地图,MainActivity需要告知Fragment地图状态已经发生了变化,需要更新Poi数据了.那么Fragment在接收到这条广播的时候,就知道地图状态已经改变,需要根据当前的中心点坐标搜索出现在的Poi数据,然后通过adapter.notifyDataSetChanged来更新ListView里面的数据即可.

/**
   * 第一次加载的时候由Activity搜索,将数据传递给Fragment,后续由Fragment来完成搜索功能
   * */

Bundle allPoiBundle = new Bundle();
allPoiBundle.putParcelableArrayList("allPoiData", (ArrayList<? extends Parcelable>) allPoiData);
allPoiFragment.setArguments(allPoiBundle);

//获取数据,只需要在OnCreateView获取
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_all, null);
    allPoiSearch = PoiSearch.newInstance();
    allData.clear();
    allData = getArguments().getParcelableArrayList("allPoiData");
    initView(view);
    return view;
}

  这里我们可以看到我只在MainActivity搜索了一次Poi,如果我们每次都在MainActivity中搜索完Poi然后再传递Fragment的话,这样其实会耗费大量的时间,数据更新的速度也比较的慢,大家可以去试试每次在MainActivity中定位完数据之后再发送个Fragment.看看这样实现是否优雅.其实我们也可以完全不在MainActivity中搜索Poi,完全交给Fragment其实也是可以的.

  这里还需要说一下Fragment的一个数据预加载问题,我们都知道Fragment是有预加载机制的,默认情况下Fragment只会预加载一页数据,因此这里我改变了它的预加载数量.

 /**
   * 这里修改了Fragment的预加载数量,一次加载三页数据,默认是一页
   * */
viewPager.setOffscreenPageLimit(3);

改变这个也是有原因的,因为我们需要在OnAttach时为Fragment注册一个广播,监听地图状态是否发生了变化,如果使用默认的加载机制,比如说我们现在就在全部这个Fragment页面,那么只有全部和写字楼注册了这个广播,其他两个页面还没有OnAttach到Activity上,这时我们改变地图状态,前面这两页数据会发生明显变化,而后面的两页是根本不知道数据已经变化了.同理一样.如果我们在最后一页,前两页已经被销毁,已经onDetach()Activity了,那么这两页也是拿不到数据的.因此我这里改变了它的预加载数量.无论如何滑动,都能够接收到数据.使用默认的预加载机制,出现问题的主要原因其实和Fragment的生命周期有紧密关联的.有空我会去写一篇关于Fragment的生命周期的博客.现在我们只需要知道就可以了.

  最后就是这个蛋疼的搜索框,浪费了我相当长的时间.按照ele的效果来看,当点击搜索框的时候,需要弹出一个页面覆盖掉这个页面,然后根据关键字搜索出数据,以列表项的形式展现出来,其实这里就使用到了在下建议查询,根据我们输入的关键字搜素出相应的数据信息.但是这里蛋疼的问题在于当我们点击返回的键的时候不是结束这个Activity,而是返回到地图这个页面.因此这里我这里只能重写onKeyDown事件,然后拦截Back事件.如果搜索框中的EditText在获取焦点状态的情况下,点击返回键的话,那么返回地图页面,一直不结束这个Activity,但是蛋疼的事就来了,当返回到这个MapView页面的时候,搜索框中的EditText仍然优先获取到了焦点,无论我们怎么点击返回键,这个Activity都不会被销毁.这样就有很大的问题.最后我找到了一种方法,只能让整个搜索框这个布局去抢占EditText的焦点.那么在返回地图的时候,EditText就永远不会优先获取到焦点事件了.而且还能够正常销毁Activity.

 /**
     * 监听onKeyDown事件
     * 目的是判断当前页面是地图显示页面还是在线建议查询页面
     * */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (isFocus) {
                inputPoiSearchLayout.setVisibility(View.GONE);
                location_name.setText("");
                location_name.clearFocus();
                keyWordPoiData.clear();
                layout.setFocusable(true);
                layout.setFocusableInTouchMode(true);
                layout.requestFocus();
                isFocus = false;
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

该说的也就这么多了,用上的知识点,以及如何具体实现.最后放上一个源代码.还有一些需要注意的就是如果使用Android Studio开发.并且jar包都保存在libs文件夹中的话,在build.gradle中别忘了配置.

sourceSets {
        main {
            jniLibs.srcDir ‘libs‘  //这里必须要有,否则会报.so文件的异常
        }
        instrumentTest.setRoot(‘tests‘)
        debug.setRoot(‘build-types/debug‘)
        release.setRoot(‘build-types/release‘)
    }

源代码(链接) http://pan.baidu.com/s/1nuKcdM5

 

 
时间: 2024-08-08 22:09:36

Android之仿ele地图定位效果的相关文章

Android PopupWindow 仿微信弹出效果

项目中,我需要PopupWindow的时候特别多,这个东西也特别的好使,所以我今天给大家写一款PopupWindow 仿微信弹出效果,这样大家直接拿到项目里就可以用了!首先让我们先看效果: 那么我首先先看下布局代码非常简单:如下 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pop_layout" android:layout_

【Android】仿UC网络判断效果

[Android]仿UC网络判断效果 利用BroadcastReceive广播接收器来监听网络状态的变化,然后呼出自定义窗口Activity来进行网络的打开关闭操作. 下载地址:http://www.devstore.cn/code/info/278.html 运行截图: 热门源码下载: 高仿京东商城 Android快速开发不可或缺的11个工具类 Android快速开发框架LoonAndroid Android应用源码比较不错的新闻客户端 版权声明:本文为博主原创文章,未经博主允许不得转载.

Android开发实现高德地图定位

一. 要实现高德地图定位呢,首先需要做好以下几步准备: 1. 在高德开放平台注册帐号 注册地址:http://lbs.amap.com 2. 在开发中下载Android平台下的 地图SDK和定位SDK文件 进入相关下载下载自己想要的功能或文件,图只是截取了地图SDK的页面,定位SDK也是一样,按自己想要的文件下载.下载完成后解压得到: - 3D地图包解压后得到:3D地图显示包"AMap_3DMap_VX.X.X_时间.jar"和库文件夹(包含armeabi.arm64-v8a等库文件)

Android应用之——百度地图定位返回4.9E-324的解决方案

用百度定位的时候一直定位不到,拿到的经纬度都是4.9E-324,Google了一下,发现不少人出现这个问题,经过一番研究,最终解决了这个问题. 目前看来,出现这个问题说明定位失败了,定位失败返回的就是这个值,定位失败的原因就是库加载失败. 也就是百度地图最开始进行初始化的时候失败了,所以返回了这个错误. 网上一般有这么几种情况: 情况一: libs里面缺少armeabi-v7a文件夹 参考:http://johnnyg.iteye.com/blog/1939126 网上搜到有人说"请检查你写的应

Android之仿今日头条标题栏效果

学习Android应用开发已经有一段时间了,对涉及应用开发的主要基础知识已经有了一定的了解,学习过程中写的博客被我整理成立了一个专栏<Android应用开发基础>.但是基本上写的代码都是一些单一知识点的演示Demo,与一个完整的产品相差甚远.要具备开发复杂的产品级应用的能力,在掌握了应用开发的基础知识的前提下,最好的方法莫过于模仿别人开发的优秀应用.在模仿中循序渐进,以程序员角度去看待每一个APP是如何实现的,它有什么优缺点,并从中提升自己.模范别人应用其实就是一种开发的学习手段,因为如果自己

Android Studio之高德地图实现定位和3D地图显示

在应用开发中,地图开发是经常需要使用的"组件",国内比较出名的是就是百度地图和高德地图. 此博客讲的是高德地图实现定位和3D地图显示,并标注相应位置,话不多说,先看看效果,在上代码. 效果如图: 首先注册高德成为开发者(打开高德地图,点击底部的开发者平台),创建应用,按照要求填写相应信息,如下图: 途中包含了发布版的SHA1安全码和测试版SHA1安全码,两者的值可以看  博客 :Android Studio apk打包,keystore.jks文件生成,根据keystore密钥获取SH

Android 百度地图定位(手动+自动) 安卓开发教程

近由于项目需要,研究了下百度地图定位,他们提供的实例基本都是用监听器实现自动定位的.我想实现一种效果:当用户进入UI时,不定位,用户需要定位的时候,自己手动点击按钮,再去定位当前位置.  经过2天研究和咨询,找到了解决方案,在此备忘一下. 注意:定位使用真机才能够真正定位:模拟器的话,在DDMS中的Emulator Control中,选择Manual,下面单选按钮选择Decimal,然后填写经纬度,send后,再点击定位我的位置按钮,就能定位了(这应该算是固定定位,哈哈...). 1.第一步当然

Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭【学习鸿洋_视频博客笔记总结】

学习鸿洋博客:http://blog.csdn.net/lmj623565791/article/details/39257409 学习鸿洋视频:慕课网视频 看看Android 高仿 QQ5.0 侧滑菜单效果 自定义控件实现效果: 技术上,继承HorizontalScrollView 加上自定义ViewGroup来实现: 1.onMeasure:决定内部View(子View)的宽和高,以及自己的宽和高 2.onLayout:决定子View的放置位置 3.onTouchEvent[监听动作] 自定

android 仿ppt进入动画效果合集

EnterAnimation android 仿ppt进入动画效果合集, 百叶窗效果,擦除效果,盒状效果,阶梯效果,菱形效果,轮子效果,劈裂效果,棋盘效果, 切入效果,扇形展开效果,十字扩展效果,随机线条效果,向内溶解效果,圆形扩展效果, 适用于各种view和viewgroup,activity即用于页面根部viewgroup, 自定义viewgroup自动换行layout, 看效果图 Series of entrance animation effects just like ppt in A