Android 高仿造微信发送位置(高德地图版)

本文出自 “阿敏其人” 简书博客,转载或引用请注明出处。

小二,来我上两张图。

来吧,我们先来看一下原版的微信发送位置
嗯,是发送位置,为什么不带发送实时位置,缺个另外一个真机。嗯,买一个16年出的google亲儿子,嗯,信仰充值先想想就好!!!

微信原版发送位置.gif

接下来,再来看一下自己的程序gif

发送位置.gif

嗯哼,看完啦。

一、发送位置的需求分析

从原版微信的gif当中,我们看到,大概可以分为这么几个行为
1、进入页面,产生两个标记点,周围地点列表。
两个标记点 一个是固定不变的当前位置的定位圆形标记,一个是可移动的红色标记。并且,会根据当前经纬度改变位置。
地址列表 就是根据当前刚进入页面的经纬度搜索的出来的 附近poi (附近兴趣点)
2、当我们点击周围点的列表,列表更新圆形绿色切换,这点没什么好说,需要注意的是
地图会动态改变位置
可移动的地图上的红色标记处于地图的中心点位置
3、当我们手动拖动地图,这时候两点注意
当手势松开的时候,可移动红色标记移动并且居中
周围poi列表信息更新,而且第一条信息是我们当前屏幕的中心点所获取的地址,这个地址 逆地里编码 得到的,即经纬度转地址
4、点击搜索条关键字,按关键字进行搜索展示列表
第一个poi信息作为默认选择item
如果我们不按下item,直接返回,那么之前页面的信息不变,地址照旧
如果我们按下item,那么该item作为之前页面的poi地址列表第一条item,并且搜索附近的poi信息。

(poi即兴趣点)

嗯,大概这么就是介么个样子,页面简单,写成文字还是看起来巴拉巴拉一大堆的。我们的demo大概也就是围绕着上面几点展开的。

二、环境说明

  • 当前微信版本:6.3.25
  • android高德地图版本:


    高德地图版本.png

16年9月份官网给的。

  • 测试机器:菊花荣耀7,Android6.0
  • IDE: AS

嗯,交代完毕。

三、开码

我们这里涉及到三个Activity,
分别是
JwActivity 得到定位,暂且叫做 A页面
ShareLocActivity 发送位置页面 暂且叫做 B页面
SeaechTextAddressActivity 搜索页面 暂且叫做 C页面

三.1、发送位置,最基本我们需要获得定位

之前弄得工具类,客官您将就着用

/**
 * User: LJM
 * Date&Time: 2016-08-17 & 22:36
 * Describe: 获取经纬度工具类
 *
 * 需要权限
 *     <!--用于进行网络定位-->
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
 <!--用于访问GPS定位-->
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
 <!--获取运营商信息,用于支持提供运营商信息相关的接口-->
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
 <!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
 <!--这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
 <!--用于访问网络,网络定位需要上网-->
 <uses-permission android:name="android.permission.INTERNET"></uses-permission>
 <!--用于读取手机当前的状态-->
 <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
 <!--写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据-->
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
 需要在application 配置的mate-data 和sevice
 <service android:name="com.amap.api.location.APSService" >
 </service>
 <meta-data
 android:name="com.amap.api.v2.apikey"
 android:value="60f458d237f0494627e196293d49db7e"/>
 另外,还需要一个key xxx.jks
 *
 */
public  class AMapLocUtils implements AMapLocationListener {
    private AMapLocationClient locationClient = null;  // 定位
    private AMapLocationClientOption locationOption = null;  // 定位设置
    @Override
    public void onLocationChanged(AMapLocation aMapLocation) {
        mLonLatListener.getLonLat(aMapLocation);
        locationClient.stopLocation();
        locationClient.onDestroy();
        locationClient = null;
        locationOption = null;
    }

    private LonLatListener mLonLatListener;
    public void  getLonLat(Context context, LonLatListener lonLatListener){
        locationClient = new AMapLocationClient(context);
        locationOption = new AMapLocationClientOption();
        locationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);// 设置定位模式为高精度模式
        locationClient.setLocationListener(this);// 设置定位监听
        locationOption.setOnceLocation(false); // 单次定位
        locationOption.setNeedAddress(true);//逆地理编码
        mLonLatListener = lonLatListener;//接口
        locationClient.setLocationOption(locationOption);// 设置定位参数
        locationClient.startLocation(); // 启动定位
    }
    public interface  LonLatListener{
        void getLonLat(AMapLocation aMapLocation);
    }
}

好啦,调用一下,奔着分享位置的页面去拉

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_jw);
        mTvResult = (TextView) findViewById(R.id.mTvResult);
        mTvSendLoc = (TextView) findViewById(R.id.mTvSendLoc);
        mTvSendLoc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent openSend = new Intent(JwActivity.this,ShareLocActivity.class);
                openSend.putExtra("lon",mLongitude);
                openSend.putExtra("lat",mLatitude);
                openSend.putExtra("cityCode",cityCode);
                startActivity(openSend);
            }
        });
        new AMapLocUtils().getLonLat(this, new AMapLocUtils.LonLatListener() {
            @Override
            public void getLonLat(AMapLocation aMapLocation) {
                mTvResult.setText("当前经度"+aMapLocation.getLongitude()+
                        "\n当前纬度:"+aMapLocation.getLatitude()+
                        "\n当前城市:"+aMapLocation.getProvince()+aMapLocation.getCity()+
                        aMapLocation.getAddress());
                mLongitude = aMapLocation.getLongitude();
                mLatitude = aMapLocation.getLatitude();
                cityCode = aMapLocation.getCityCode();
                mTvSendLoc.setVisibility(View.VISIBLE);
            }
        });
    }

三.2、 逆地理编码 经纬度转地址

从这里开始,我们就跳到了B页面啦~~~

B页面拿到A页面的经纬度之后,就开始心急火燎地想把经纬度转地址啦
这个时候 逆地理编码 出现了。

逆地理编码 大概是这么几步走的
1、得到GeocodeSearch的实例
2、实现GeocodeSearch.OnGeocodeSearchListener接口
3、实现接口就必须实现实现一下两方法 onRegeocodeSearched和onGeocodeSearched。

Geocode是地理编码的意思,Regeocode就是逆地理编码的。

所以我们主要逆地理实现逻辑都在onRegeocodeSearched方法

转成代码大概就是:

step1:

private GeocodeSearch geocoderSearch;

step2

geocoderSearch = new GeocodeSearch(this);

step3

    /**
     * 根据经纬度得到地址
     */
    public void getAddress(final LatLng latLonPoint) {
        // 第一个参数表示一个Latlng,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系
        RegeocodeQuery query = new RegeocodeQuery(convertToLatLonPoint(latLonPoint), 200, GeocodeSearch.AMAP);
        geocoderSearch.getFromLocationAsyn(query);// 设置同步逆地理编码请求
    }

    /**
     * 逆地理编码回调
     */
    @Override
    public void onRegeocodeSearched(RegeocodeResult result, int rCode) {
        if (rCode == 1000) {
            if (result != null && result.getRegeocodeAddress() != null
                    && result.getRegeocodeAddress().getFormatAddress() != null) {
                addressName = result.getRegeocodeAddress().getFormatAddress(); // 逆转地里编码不是每次都可以得到对应地图上的opi
                L.d("逆地理编码回调  得到的地址:" + addressName);
                mAddressEntityFirst = new AddressSearchTextEntity(addressName, addressName, true, convertToLatLonPoint(mFinalChoosePosition));

            } else {
                ToastUtil.show(ShareLocActivity.this, R.string.no_result);
            }
        } else if (rCode == 27) {
            ToastUtil.show(this, R.string.error_network);
        } else if (rCode == 32) {
            ToastUtil.show(this, R.string.error_key);
        } else {
            ToastUtil.show(this,
                    getString(R.string.error_other) + rCode);
        }
    }

    /**
     * 地理编码查询回调
     */
    @Override
    public void onGeocodeSearched(GeocodeResult result, int rCode) {
    }

返回码1000表示转换成功,拿到我们RegeocodeResult的形参我们可以得到地址。

看个大概就行,后面附上这个页面的完整代码。

三.3、根据经纬度搜索周围poi信息

poi搜索分 搜索关键字 和 搜索经纬度。

官网的demo提供了搜索关键字的,但是没有�相应的按照经纬度的,其实做起来也差不多,但是一开始看文档找呀找找不到,为什么不也示例一下。

其实使用方法也是比较类似的。

  • 1、首先我们要得到private PoiSearch.Query 的实例
  • 2、设置 按需求设置搜索配置
    • 2.1、按经纬度搜索该点周围的poi信息
    /**
     * 开始进行poi搜索   重点
     * 通过经纬度获取附近的poi信息
     * <p>
     * 1、keyword 传 ""
     * 2、poiSearch.setBound(new PoiSearch.SearchBound(lpTemp, 5000, true)); 根据
     */
    protected void doSearchQuery() {

        currentPage = 0;
        query = new PoiSearch.Query("", "", city);// 第一个参数表示搜索字符串,第二个参数表示poi搜索类型,第三个参数表示poi搜索区域(空字符串代表全国)
        query.setPageSize(20);// 设置每页最多返回多少条poiitem
        query.setPageNum(currentPage);// 设置查第一页

        LatLonPoint lpTemp = convertToLatLonPoint(mFinalChoosePosition);

        if (lpTemp != null) {
            poiSearch = new PoiSearch(this, query);
            poiSearch.setOnPoiSearchListener(this);  // 实现  onPoiSearched  和  onPoiItemSearched
            poiSearch.setBound(new PoiSearch.SearchBound(lpTemp, 5000, true));//
            // 设置搜索区域为以lp点为圆心,其周围5000米范围
            poiSearch.searchPOIAsyn();// 异步搜索
        }
    }
  • 2.2、按照关键字搜索附近的poi信息
    /**
     * 按照关键字搜索附近的poi信息
     * @param key
     */
    protected void doSearchQueryWithKeyWord(String key) {
        currentPage = 0;
        query = new PoiSearch.Query(key, "", city);// 第一个参数表示搜索字符串,第二个参数表示poi搜索类型,第三个参数表示poi搜索区域(空字符串代表全国)
        query.setPageSize(20);// 设置每页最多返回多少条poiitem
        query.setPageNum(currentPage);// 设置查第一页

        if (lp != null) {
            poiSearch = new PoiSearch(this, query);
            poiSearch.setOnPoiSearchListener(this);   // 实现  onPoiSearched  和  onPoiItemSearched
            poiSearch.setBound(new PoiSearch.SearchBound(lp, 5000, true));//
            // 设置搜索区域为以lp点为圆心,其周围5000米范围
            poiSearch.searchPOIAsyn();// 异步搜索
        }
    }

不管是按照关键字还是按照经纬度,我们都要实现利用setOnPoiSearchListener实现搜索poi的接口,然后实现 onPoiSearched 和 onPoiItemSearched这两个方法,在关键onPoiSearched方法里面我们可以得到搜索的poi结果集合。

  • 3、在onPoiSearched方法里面操作数据,更新列表
    /**
     * poi 附近数据搜索
     *
     * @param result
     * @param rcode
     */
    @Override
    public void onPoiSearched(PoiResult result, int rcode) {
        if (rcode == 1000) {
            if (result != null && result.getQuery() != null) {// 搜索poi的结果
                if (result.getQuery().equals(query)) {// 是否是同一条
                    poiResult = result;
                    poiItems = poiResult.getPois();// 取得第一页的poiitem数据,页数从数字0开始
                    List<SuggestionCity> suggestionCities = poiResult
                            .getSearchSuggestionCitys();// 当搜索不到poiitem数据时,会返回含有搜索关键字的城市信息
                    mDatas.clear();
                    mDatas.add(mAddressEntityFirst);// 第一个元素
                    AddressSearchTextEntity addressEntity = null;
                    for (PoiItem poiItem : poiItems) {
                        L.d("得到的数据 poiItem " + poiItem.getSnippet());
                        addressEntity = new AddressSearchTextEntity(poiItem.getTitle(), poiItem.getSnippet(), false, poiItem.getLatLonPoint());
                        mDatas.add(addressEntity);
                    }
                    if (isHandDrag) {
                        mDatas.get(0).isChoose = true;
                    }
                    mRvAddressAdapter.notifyDataSetChanged();
                }
            } else {
                ToastUtil
                        .show(ShareLocActivity.this, "对不起,没有搜索到相关数据!");
            }
        }
    }
    @Override
    public void onPoiItemSearched(PoiItem poiitem, int rcode) {
    }

这么一个流程跑下来,poi数据就拿到了。

三.4、拖动地图

实现OnCameraChangeListener接口 mAMap.setOnCameraChangeListener(this);

实现 onCameraChange 和 onCameraChangeFinish两个方法

    // 拖动地图
    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        //L.d("拖动地图 onCameraChange ");
    }
    /**
     * 拖动地图 结束回调
     *
     * @param cameraPosition 当地图位置发生变化,就重新查询数据(手动拖动或者代码改变地图位置都会调用)
     */
    @Override
    public void onCameraChangeFinish(CameraPosition cameraPosition) {
        mFinalChoosePosition = cameraPosition.target;
        L.d("拖动地图 Finish changeCenterMarker 经度" + mFinalChoosePosition.longitude + "   纬度:" + mFinalChoosePosition.latitude);
        mIvCenter.startAnimation(animationMarker);
        if (isHandDrag||isFirstLoadList) {//手动去拖动地图
            getAddress(cameraPosition.target);
            doSearchQuery();
        } else if(isBackFromSearchChoose){
            doSearchQuery();
        }else{
            mRvAddressAdapter.notifyDataSetChanged();
        }
        isHandDrag = true;
        isFirstLoadList = false;
    }

这里需要注意的是,

mAMap.moveCamera方法可以通过代码手动移动地图,他会自动调用onCameraChangeFinish方法(OnCameraChangeListener按道理也是会的)

mAMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lp.getLatitude(), lp.getLongitude()), 20));

嗯,大概就是这样子了。

至于C页面(就是我们在B页面按下搜索键跳转的页面,他其实也就是关键字搜索而且)

四、完整代码

接下我们看一下完整的B页面和C页面的代码把

** B页面,分享位置页面 **

public class ShareLocActivity extends CheckPermissionsActivity implements View.OnClickListener,
        AMap.OnMapClickListener,
        PoiSearch.OnPoiSearchListener, AMap.OnCameraChangeListener, Animation.AnimationListener, GeocodeSearch.OnGeocodeSearchListener {
    private static final int OPEN_SEARCH = 0X0001;
    private MapView mapview;
    private AMap mAMap;
    private PoiResult poiResult; // poi返回的结果
    private int currentPage = 0;// 当前页面,从0开始计数
    private PoiSearch.Query query;// Poi查询条件类
    private LatLonPoint lp;//
    private Marker locationMarker; // 选择的点
    private PoiSearch poiSearch;
    private List<PoiItem> poiItems;// poi数据
    private RelativeLayout mPoiDetail;
    private TextView mPoiName, mPoiAddress;
    private String keyWord = "";
    private String city;
    private TextView mTvHint;
    private RelativeLayout search_bar_layout;

    private ImageView mIvCenter;
    private Animation animationMarker;
    private LatLng mFinalChoosePosition; //最终选择的点
    private GeocodeSearch geocoderSearch;

    private String addressName;
    private RecyclerView mRvAddress;
    private RvAddressSearchTextAdapter mRvAddressAdapter;
    private ArrayList<AddressSearchTextEntity> mDatas = new ArrayList<>();
    private AddressSearchTextEntity mAddressEntityFirst = null;
    private TextView mTvSearch;
    private boolean isHandDrag = true;
    private boolean isFirstLoadList = true;
    private boolean isBackFromSearchChoose = false;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share_loc);

        Intent intent = getIntent();
        double lon = intent.getDoubleExtra("lon", 0);
        double lat = intent.getDoubleExtra("lat", 0);
        city = intent.getStringExtra("cityCode");
        lp = new LatLonPoint(lat, lon);

        mapview = (MapView) findViewById(R.id.mapView);
        mIvCenter = (ImageView) findViewById(R.id.mIvCenter);

        mapview.onCreate(savedInstanceState);
        animationMarker = AnimationUtils.loadAnimation(this,
                R.anim.bounce_interpolator);
        mRvAddress = (RecyclerView) findViewById(R.id.mRvAddress);
        LinearLayoutManager layoutManager = new LinearLayoutManager(ShareLocActivity.this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRvAddress.setLayoutManager(layoutManager);
        mRvAddressAdapter = new RvAddressSearchTextAdapter(ShareLocActivity.this, mDatas);

        mRvAddress.setAdapter(mRvAddressAdapter);
        mRvAddressAdapter.setOnItemClickLitener(new RvAddressSearchTextAdapter.OnItemClickLitener() {
            @Override
            public void onItemClick(View view, int position) {
                mFinalChoosePosition = convertToLatLng(mDatas.get(position).latLonPoint);
                for (int i = 0; i < mDatas.size(); i++) {
                    mDatas.get(i).isChoose = false;
                }
                mDatas.get(position).isChoose = true;
                L.d("点击后的最终经纬度:  纬度" + mFinalChoosePosition.latitude + " 经度 " + mFinalChoosePosition.longitude);
                isHandDrag = false;
                // 点击之后,我利用代码指定的方式改变了地图中心位置,所以也会调用 onCameraChangeFinish
                // 只要地图发生改变,就会调用 onCameraChangeFinish ,不是说非要手动拖动屏幕才会调用该方法
                mAMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(mFinalChoosePosition.latitude, mFinalChoosePosition.longitude), 20));
            }
            @Override
            public void onItemLongClick(View view, int position) {
            }
        });
        init();
    }

    /**
     * 初始化AMap对象
     */
    private void init() {
        if (mAMap == null) {
            mAMap = mapview.getMap();
            mAMap.setOnMapClickListener(this);
            mAMap.setOnCameraChangeListener(this);// 对amap添加移动地图事件监听器

            search_bar_layout = (RelativeLayout) findViewById(R.id.search_bar_layout);
            search_bar_layout.setOnClickListener(this);
            animationMarker.setAnimationListener(this);

            locationMarker = mAMap.addMarker(new MarkerOptions()
                    .anchor(0.5f, 0.5f)
                    .icon(BitmapDescriptorFactory
                            .fromBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.point4)))
                    .position(new LatLng(lp.getLatitude(), lp.getLongitude())));
            mFinalChoosePosition = locationMarker.getPosition();
        }
        setup();
        // 只要地图发生改变,就会调用 onCameraChangeFinish ,不是说非要手动拖动屏幕才会调用该方法
        mAMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lp.getLatitude(), lp.getLongitude()), 20));
    }

    private void setup() {
        mPoiDetail = (RelativeLayout) findViewById(R.id.poi_detail);
        mPoiDetail.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

            }
        });
        mPoiName = (TextView) findViewById(R.id.poi_name);
        mPoiAddress = (TextView) findViewById(R.id.poi_address);
        mTvHint = (TextView) findViewById(R.id.mTvHint);
        mTvHint.setOnClickListener(this);

        mTvSearch = (TextView) findViewById(R.id.mTvSearch);
        mTvSearch.setOnClickListener(this);

        geocoderSearch = new GeocodeSearch(this);
        geocoderSearch.setOnGeocodeSearchListener(this);
        mIvCenter.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ToastUtil.show(ShareLocActivity.this, "当前选择的经度:" + mFinalChoosePosition.longitude + "  纬度:" + mFinalChoosePosition.latitude);
            }
        });
    }
    
    // 拖动地图
    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        //L.d("拖动地图 onCameraChange ");
    }
    /**
     * 拖动地图 结束回调
     *
     * @param cameraPosition 当地图位置发生变化,就重新查询数据(手动拖动或者代码改变地图位置都会调用)
     */
    @Override
    public void onCameraChangeFinish(CameraPosition cameraPosition) {
        mFinalChoosePosition = cameraPosition.target;
        L.d("拖动地图 Finish changeCenterMarker 经度" + mFinalChoosePosition.longitude + "   纬度:" + mFinalChoosePosition.latitude);
        mIvCenter.startAnimation(animationMarker);
        if (isHandDrag||isFirstLoadList) {//手动去拖动地图
            getAddress(cameraPosition.target);
            doSearchQuery();
        } else if(isBackFromSearchChoose){
            doSearchQuery();
        }else{
            mRvAddressAdapter.notifyDataSetChanged();
        }
        isHandDrag = true;
        isFirstLoadList = false;
    }
    
    // ========  poi搜索 周边  以下 =====================
    /**
     * 开始进行poi搜索   重点
     * 通过经纬度获取附近的poi信息
     * <p>
     * 1、keyword 传 ""
     * 2、poiSearch.setBound(new PoiSearch.SearchBound(lpTemp, 5000, true)); 根据
     */
    protected void doSearchQuery() {

        currentPage = 0;
        query = new PoiSearch.Query("", "", city);// 第一个参数表示搜索字符串,第二个参数表示poi搜索类型,第三个参数表示poi搜索区域(空字符串代表全国)
        query.setPageSize(20);// 设置每页最多返回多少条poiitem
        query.setPageNum(currentPage);// 设置查第一页

        LatLonPoint lpTemp = convertToLatLonPoint(mFinalChoosePosition);

        if (lpTemp != null) {
            poiSearch = new PoiSearch(this, query);
            poiSearch.setOnPoiSearchListener(this);  // 实现  onPoiSearched  和  onPoiItemSearched
            poiSearch.setBound(new PoiSearch.SearchBound(lpTemp, 5000, true));//
            // 设置搜索区域为以lp点为圆心,其周围5000米范围
            poiSearch.searchPOIAsyn();// 异步搜索
        }
    }
    /**
     * poi 附近数据搜索
     *
     * @param result
     * @param rcode
     */
    @Override
    public void onPoiSearched(PoiResult result, int rcode) {
        if (rcode == 1000) {
            if (result != null && result.getQuery() != null) {// 搜索poi的结果
                if (result.getQuery().equals(query)) {// 是否是同一条
                    poiResult = result;
                    poiItems = poiResult.getPois();// 取得第一页的poiitem数据,页数从数字0开始
                    List<SuggestionCity> suggestionCities = poiResult
                            .getSearchSuggestionCitys();// 当搜索不到poiitem数据时,会返回含有搜索关键字的城市信息
                    mDatas.clear();
                    //if(isFirstLoadList || isBackFromSearchChoose){
                    mDatas.add(mAddressEntityFirst);// 第一个元素

                    AddressSearchTextEntity addressEntity = null;
                    for (PoiItem poiItem : poiItems) {
                        L.d("得到的数据 poiItem " + poiItem.getSnippet());
                        addressEntity = new AddressSearchTextEntity(poiItem.getTitle(), poiItem.getSnippet(), false, poiItem.getLatLonPoint());
                        mDatas.add(addressEntity);
                    }
                    if (isHandDrag) {
                        mDatas.get(0).isChoose = true;
                    }
                    mRvAddressAdapter.notifyDataSetChanged();
                }
            } else {
                ToastUtil
                        .show(ShareLocActivity.this, "对不起,没有搜索到相关数据!");
            }
        }
    }

    @Override
    public void onPoiItemSearched(PoiItem poiitem, int rcode) {

    }
    /**
     * 按照关键字搜索附近的poi信息
     * @param key
     */
    protected void doSearchQueryWithKeyWord(String key) {
        currentPage = 0;
        query = new PoiSearch.Query(key, "", city);// 第一个参数表示搜索字符串,第二个参数表示poi搜索类型,第三个参数表示poi搜索区域(空字符串代表全国)
        query.setPageSize(20);// 设置每页最多返回多少条poiitem
        query.setPageNum(currentPage);// 设置查第一页

        if (lp != null) {
            poiSearch = new PoiSearch(this, query);
            poiSearch.setOnPoiSearchListener(this);   // 实现  onPoiSearched  和  onPoiItemSearched
            poiSearch.setBound(new PoiSearch.SearchBound(lp, 5000, true));//
            // 设置搜索区域为以lp点为圆心,其周围5000米范围
            poiSearch.searchPOIAsyn();// 异步搜索
        }
    }
    // ========  poi搜索 周边  以上   =====================
    /**
     * 根据经纬度得到地址
     */
    public void getAddress(final LatLng latLonPoint) {
        // 第一个参数表示一个Latlng,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系
        RegeocodeQuery query = new RegeocodeQuery(convertToLatLonPoint(latLonPoint), 200, GeocodeSearch.AMAP);
        geocoderSearch.getFromLocationAsyn(query);// 设置同步逆地理编码请求
    }

    /**
     * 逆地理编码回调
     */
    @Override
    public void onRegeocodeSearched(RegeocodeResult result, int rCode) {
        if (rCode == 1000) {
            if (result != null && result.getRegeocodeAddress() != null
                    && result.getRegeocodeAddress().getFormatAddress() != null) {
                addressName = result.getRegeocodeAddress().getFormatAddress(); // 逆转地里编码不是每次都可以得到对应地图上的opi
                L.d("逆地理编码回调  得到的地址:" + addressName);
                mAddressEntityFirst = new AddressSearchTextEntity(addressName, addressName, true, convertToLatLonPoint(mFinalChoosePosition));
            } else {
                ToastUtil.show(ShareLocActivity.this, R.string.no_result);
            }
        } else if (rCode == 27) {
            ToastUtil.show(this, R.string.error_network);
        } else if (rCode == 32) {
            ToastUtil.show(this, R.string.error_key);
        } else {
            ToastUtil.show(this,
                    getString(R.string.error_other) + rCode);
        }
    }

    /**
     * 地理编码查询回调
     */
    @Override
    public void onGeocodeSearched(GeocodeResult result, int rCode) {
    }
    /**
     * 把LatLonPoint对象转化为LatLon对象
     */
    public LatLng convertToLatLng(LatLonPoint latLonPoint) {
        return new LatLng(latLonPoint.getLatitude(), latLonPoint.getLongitude());
    }

    /**
     * 把LatLng对象转化为LatLonPoint对象
     */
    public static LatLonPoint convertToLatLonPoint(LatLng latlon) {
        return new LatLonPoint(latlon.latitude, latlon.longitude);
    }
    
    /**
     * 方法必须重写
     */
    @Override
    protected void onResume() {
        super.onResume();
        mapview.onResume();
        whetherToShowDetailInfo(false);
    }

    /**
     * 方法必须重写
     */
    @Override
    protected void onPause() {
        super.onPause();
        mapview.onPause();
    }

    /**
     * 方法必须重写
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapview.onSaveInstanceState(outState);
    }

    /**
     * 方法必须重写
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapview.onDestroy();
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.mTvHint:
            case R.id.search_bar_layout:
                Intent intent = new Intent(ShareLocActivity.this, SeaechTextAddressActivity.class);
                intent.putExtra("point", mFinalChoosePosition);
                startActivityForResult(intent, OPEN_SEARCH);
                isBackFromSearchChoose = false;
                break;
            case R.id.mTvSearch:
                AddressSearchTextEntity finalChooseEntity = null;
                for (AddressSearchTextEntity searchTextEntity : mDatas) {
                    if (searchTextEntity.isChoose) {
                        finalChooseEntity = searchTextEntity;
                    }
                }
                if (finalChooseEntity != null) {
                    L.d("最终点击发送到要上一页的数据:"
                            + "\n 经度" + finalChooseEntity.latLonPoint.getLongitude()
                            + "\n 纬度" + finalChooseEntity.latLonPoint.getLatitude()
                            + "\n 地址" + finalChooseEntity.mainAddress
                    );
                    ToastUtil.show(ShareLocActivity.this,"最终点击发送到要上一页的数据:"
                            + "\n 经度" + finalChooseEntity.latLonPoint.getLongitude()
                            + "\n 纬度" + finalChooseEntity.latLonPoint.getLatitude()
                            + "\n 地址" + finalChooseEntity.mainAddress);
                }
                break;
            default:
                break;
        }
    }
    
    private void whetherToShowDetailInfo(boolean isToShow) {
        if (isToShow) {
            mPoiDetail.setVisibility(View.VISIBLE);

        } else {
            mPoiDetail.setVisibility(View.GONE);
        }
    }

    // 单击地图
    @Override
    public void onMapClick(LatLng latlng) {
        ToastUtil.show(ShareLocActivity.this, "点击地图结果:  经度:" + latlng.longitude + "   纬度: " + latlng.latitude);
    }
    /**
     * poi没有搜索到数据,返回一些推荐城市的信息
     */
    private void showSuggestCity(List<SuggestionCity> cities) {
        String infomation = "推荐城市\n";
        for (int i = 0; i < cities.size(); i++) {
            infomation += "城市名称:" + cities.get(i).getCityName() + "城市区号:"
                    + cities.get(i).getCityCode() + "城市编码:"
                    + cities.get(i).getAdCode() + "\n";
        }
        ToastUtil.show(this, infomation);
    }
    
    // 动画复写的三个方法
    @Override
    public void onAnimationStart(Animation animation) {
        mIvCenter.setImageResource(R.drawable.poi_marker_pressed);
    }
    @Override
    public void onAnimationRepeat(Animation animation) {

    }
    @Override
    public void onAnimationEnd(Animation animation) {
        mIvCenter.setImageResource(R.drawable.poi_marker_pressed);
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == OPEN_SEARCH && resultCode == RESULT_OK) {
            AddressSearchTextEntity backEntity = (AddressSearchTextEntity) data.getParcelableExtra("backEntity");
            mAddressEntityFirst = backEntity; // 上一个页面传过来的 item对象
            mAddressEntityFirst.isChoose = true;

            isBackFromSearchChoose = true;
            isHandDrag = false;
            mAMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(backEntity.latLonPoint.getLatitude(), backEntity.latLonPoint.getLongitude()), 20));
        }
    }
}

嗯。看起来长了一点,客官如果看到了这里也挺不容易的,就权且当个参考吧。哈哈哈

.
.
C页面

public class SeaechTextAddressActivity extends CheckPermissionsActivity implements PoiSearch.OnPoiSearchListener {
    private EditText mEtContent;
    private TextView mTvSearch;
    private String mSearchText;
    private LatLonPoint lp;//
    private PoiResult poiResult; // poi返回的结果
    private List<PoiItem> poiItems;// poi数据
    private int currentPage = 0;// 当前页面,从0开始计数
    private PoiSearch.Query query;// Poi查询条件类
    private PoiSearch poiSearch;

    private RecyclerView mRvSearchText;
    private RvAddressSearchTextAdapter mRvAddressSearchTextAdapter;
    private ArrayList<AddressSearchTextEntity> mDatas = new ArrayList<>();
    //private AddressSearchTextEntity mAddressTextFirst = null;

    private String city = "深圳市"; // 这个需要完善 不能写死

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search_text_address);
        initView();
    }

    private void initView() {
        mEtContent = (EditText) findViewById(R.id.mEtContent);
        mTvSearch = (TextView) findViewById(R.id.mTvSearch);
        mRvSearchText = (RecyclerView) findViewById(R.id.mRvSearchText);
        LatLng point = (LatLng) getIntent().getParcelableExtra("point");
        lp=new LatLonPoint(point.latitude,point.longitude);

        // Rv 列表
        mRvSearchText = (RecyclerView) findViewById(R.id.mRvSearchText);
        LinearLayoutManager layoutManager = new LinearLayoutManager(SeaechTextAddressActivity.this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRvSearchText.setLayoutManager(layoutManager);

        mRvAddressSearchTextAdapter = new RvAddressSearchTextAdapter(SeaechTextAddressActivity.this,mDatas);
        mRvSearchText.setAdapter(mRvAddressSearchTextAdapter);
        mRvAddressSearchTextAdapter.setOnItemClickLitener(new RvAddressSearchTextAdapter.OnItemClickLitener() {
            @Override
            public void onItemClick(View view, int position) {
                Intent intent =new Intent();

                AddressSearchTextEntity addressSearchTextEntity = mDatas.get(position);
                intent.putExtra("backEntity",addressSearchTextEntity);
                setResult(RESULT_OK,intent);
                finish();

            }
            @Override
            public void onItemLongClick(View view, int position) {

            }
        });


        mTvSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mSearchText = mEtContent.getText().toString().trim();
                if (TextUtils.isEmpty(mSearchText)) {
                    ToastUtil.show(SeaechTextAddressActivity.this, "请输入搜索关键字");
                    return;
                } else {
                    doSearchQueryWithKeyWord(mSearchText);
                    KeyBoardUtils.closeKeybord(mEtContent,SeaechTextAddressActivity.this);
                }
            }
        });
    }
    
    protected void doSearchQueryWithKeyWord(String key) {
        currentPage = 0;
        query = new PoiSearch.Query(key, "", city);// 第一个参数表示搜索字符串,第二个参数表示poi搜索类型,第三个参数表示poi搜索区域(空字符串代表全国)
        query.setPageSize(20);// 设置每页最多返回多少条poiitem
        query.setPageNum(currentPage);// 设置查第一页
        query.setCityLimit(true); //限定城市

        if (lp != null) {
            poiSearch = new PoiSearch(this, query);
            poiSearch.setOnPoiSearchListener(this);   // 实现  onPoiSearched  和  onPoiItemSearched
            poiSearch.setBound(new PoiSearch.SearchBound(lp, 5000, true));//
            // 设置搜索区域为以lp点为圆心,其周围5000米范围
            poiSearch.searchPOIAsyn();// 异步搜索
        }

    }


    @Override
    public void onPoiSearched(PoiResult result, int rcode) {
        if (rcode == 1000) {
            if (result != null && result.getQuery() != null) {// 搜索poi的结果
                if (result.getQuery().equals(query)) {// 是否是同一条
                    poiResult = result;
                    poiItems = poiResult.getPois();// 取得第一页的poiitem数据,页数从数字0开始
                    List<SuggestionCity> suggestionCities = poiResult
                            .getSearchSuggestionCitys();// 当搜索不到poiitem数据时,会返回含有搜索关键字的城市信息

                    mDatas.clear();
                    //mDatas.add(mAddressTextFirst);// 第一个元素
                    AddressSearchTextEntity addressEntity = null;
                    for (int i=0;i<poiItems.size();i++) {
                        PoiItem poiItem = poiItems.get(i);
                        if(i==0){
                            addressEntity = new AddressSearchTextEntity(poiItem.getTitle(),poiItem.getSnippet(),true,poiItem.getLatLonPoint());
                        }else{
                            addressEntity = new AddressSearchTextEntity(poiItem.getTitle(),poiItem.getSnippet(),false,poiItem.getLatLonPoint());
                        }
                        L.d("得到的数据 poiItem "
                          + "\npoiItem.getSnippet()"+poiItem.getSnippet()
                          + "\npoiItem.getAdCode()"+poiItem.getAdCode()
                          + "\npoiItem.getAdName()"+poiItem.getAdName()
                          + "\npoiItem.getDirection()"+poiItem.getDirection()
                          + "\npoiItem.getBusinessArea()"+poiItem.getBusinessArea()
                          + "\npoiItem.getCityCode()"+poiItem.getCityCode()
                          + "\npoiItem.getEmail()"+poiItem.getEmail()
                          + "\npoiItem.getParkingType()"+poiItem.getParkingType()
                          + "\npoiItem.getCityName()"+poiItem.getCityName()
                          + "\npoiItem.getProvinceName()"+poiItem.getProvinceName()
                          + "\npoiItem.getSnippet()"+poiItem.getSnippet()
                          + "\npoiItem.getTitle()"+poiItem.getTitle()
                          + "\npoiItem.getTypeDes()"+poiItem.getTypeDes()
                          + "\npoiItem.getDistance()"+poiItem.getDistance()
                          + "\npoiItem.getWebsite()"+poiItem.getWebsite()
                               );

                        mDatas.add(addressEntity);
                    }
                    mRvAddressSearchTextAdapter.notifyDataSetChanged();
                }
            } else {
                ToastUtil
                        .show(SeaechTextAddressActivity.this, "对不起,没有搜索到相关数据!");
            }
        }
    }

    @Override
    public void onPoiItemSearched(PoiItem poiItem, int i) {

    }
}

嗯,到这里就差不多了。
其实结合官方demo,折腾起来也就差不多了。
程序有一个小bug,微信拖动地图的时候,基本上算作是精准的,但是我们这里移动地图红色标记选择一个点然后松开手指之后,有时候没办法准确地拿到当前停留的点的准确地址。
对于这个bug,其实我也不想,但是高德给我的逆地理编码确实就是出不来的,有时很大一个范围拖动逆地理出来的都是同一个地址,如果我把点选在某一个大酒店或者标志性的地方的时候,是没什么问题的。


我眺望远方的山峰 却错过转弯的路口
蓦然回首 才发现你在等我 没离开过
我寻找大海的尽头 却不留蜿蜒的河流
当我逆水行舟 你在我左右 推着我走
……

网易大晚上推过来的歌听起来好激情~~~


如果小兴趣看下小弟Google Map的小文,请移步:Android Google Map/谷歌地图 接入不完全指南 (一)

本篇完。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容