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/1mhMQumc

 

 

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

  1. Android PopupWindow 仿微信弹出效果

    项目中,我须要PopupWindow的时候特别多,这个东西也特别的好使,所以我今天给大家写一款PopupWindow 仿微信弹出效果.这样大家直接拿到项目里就能够用了! 首先让我们先看效果: 那么我首 ...

  2. Android开发实现高德地图定位

    1.获取Key 参考官方文档:http://lbs.amap.com/api/android-location-sdk/guide/create-project/get-key 对于签名文件的获取建议 ...

  3. android开发对应高德地图定位服务进度一

    进行android的高德地图开发首先需要进入高德地图的控制台进行注册登录.之后创建新的应用并且绑定软件得到相应的key. 这里面需要找到自己软件对应的多个SHA1.这里有发布版和调试版,以及对应的软件 ...

  4. android采用MVP完整漫画APP、钉钉地图效果、功能完善的音乐播放器、仿QQ动态登录效果、触手app主页等源码

    Android精选源码 一个可以上拉下滑的Ui效果,觉得好看可以学学 APP登陆页面适配 一款采用MVP的的完整漫画APP源码 android实现钉钉地图效果源码 一个使用单个文字生成壁纸图片的app ...

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

    近由于项目需要,研究了下百度地图定位,他们提供的实例基本都是用监听器实现自动定位的.我想实现一种效果:当用户进入UI时,不定位,用户需要定位的时候,自己手动点击按钮,再去定位当前位置.  经过2天研究 ...

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

    在应用开发中,地图开发是经常需要使用的“组件”,国内比较出名的是就是百度地图和高德地图. 此博客讲的是高德地图实现定位和3D地图显示,并标注相应位置,话不多说,先看看效果,在上代码. 效果如图: 首先 ...

  7. Android studio 百度地图开发(2)地图定位

    Android studio 百度地图开发(2)地图定位 email:chentravelling@163.com 开发环境:win7 64位,Android Studio,请注意是Android S ...

  8. JS仿淘宝详情页菜单条智能定位效果

    类似于淘宝详情页菜单条智能定位 对于每个人来说并不陌生!如下截图所示:红色框的那部分! 基本原理: 是用JS侦听滚动事件,当页面的滚动距离(页面滚动的高度)大于或者等于 "对象"( ...

  9. Android使用百度地图定位并显示手机位置后使用前置摄像头“偷拍”

    今天老板让我验证一下技术可行性,记录下来. 需求 :定位手机的位置并在百度地图上显示,得到位置后使用前置摄像头进行抓拍 拿到这个需求后,对于摄像头的使用不太熟悉,于是我先做了定位手机并在百度地图上显示 ...

随机推荐

  1. Java 8 forEach简单例子

    1. forEach and Map 1.1 通常这样遍历一个Map Map<String, Integer> items = new HashMap<>(); items.p ...

  2. 【TJOI&HEOI2016】【Bzoj4551】树

    这道题是可以用树链剖分来做的,但其实有比它更加简单的做法--并查集. 可以想到,这类题的一种常见做法是离线处理,先全部读入,再从后往前处理,每次遇到标记操作,就把这个点的标记次数减一,到零以后就把这个 ...

  3. SQL语句 多表基本操作

    创建四张表学生表:学号(Sno).姓名(Sname).性别(Ssex).年龄(Sage)教师表:教师编号(Tno).教师姓名(Tname)课程表:课程编号(Cno).课程名(Cname).教师编号(T ...

  4. Lesson 9 A cold welcome

    Text On Wednesday evening, we went to the Town Hall. It was the last day of the year and a large cro ...

  5. 基于HttpModule的简单.NET网站授权方案

    摘要 本文介绍一种入门级的网站授权(注:这里所指的授权指的是注册码效果,而不是网站登陆时的身份授权)方案,仅供学习交流及对付小白客户使用.复杂的网站授权涉及网站加密等一系列复杂的技术,不做本文介绍内容 ...

  6. 玩转Windows服务系列——命令行管理Windows服务

    说到Windows服务的管理就不得不说通过命令行的方式管理Windows服务,因为无论是系统管理员,还是通过编程的方式调用cmd命令,命令行都是非常方便以及强大的工具. 接下来就看一下如何通过cmd命 ...

  7. js模块化历程

    这是一篇关于js模块化历程的长长的流水账,记录js模块化思想的诞生与变迁,展望ES6模块化标准的未来.经历过这段历史的人或许会感到沧桑,没经历过的人也应该知道这段历史. 无模块时代 在ajax还未提出 ...

  8. 如何让用户只能访问特定的数据库(MSSQL)

    背景 客户的SQL Server实例上有多个厂商的数据库,每个数据库由各自的进行厂进行商维护, 为了限定不同厂商的维护人员只能访问自己的数据库,现需要给各个厂商限定权限,让他们登录SQL Server ...

  9. sql期末复习(二)

    1.概念模式是对dba所看到的全局数据逻辑结构和特征的描述 概念模式是对数据整体的逻辑结构的描述 2.数据库网状模型应满足的条件是允许一个以上的结点无父结点,其余结点都只有一个父结点 3.sql语言中 ...

  10. sizzle分析记录:分解流程

    <form> <label>Name:</label> <input name="name" /> <fieldset> ...