Android 天气APP(二十四)地图天气(上)自动定位和地图点击定位

简介: Android 天气APP(二十四)地图天气(上)自动定位和地图点击定位

前言


之前也看过和风天气自己做的APP,主页面的地图点击之后,定位到某一个点,然后查看这个地方的天气,实际思路还是通过区县来查询天气的,只不过,加上了地图就比较的直观,看起来也会觉得很上档次,所以我也决定做一个这样的功能。

这篇文章实现的效果图如下:


20200821103400579.gif


正文


说到地图就想到了百度地图,当然你要是想用高德地图也是可以的,对接就可以了,我这里就不介绍了,还记得在第一篇文章的时候,就注册了百度地图开放平台的账号,并且申请了应用的key用于定位,点击百度地图开放平台进入。登录账号之后进入控制台,找到之前的那个应用,我的当然是GoodWeather,你们的要看自己的名字,


2020082015565228.png


如果你是第一次看我的文章呢,可以先看看第一篇简单了解一下我是在做什么。

地址链接:Android 天气APP(一)开发准备


一、修改应用配置


还记得吗?我之前只选择了定位这个功能,点击设置进入配置页面


20200820160106684.png


这是之前配置的。


20200820160350195.png


如下图所示勾选,然后提交


20200824110839274.png


提交之后就不用管了,点击开发文档选择Android地图SDK


20200820160825876.png


然后点击自定义下载


20200820161041830.png


按照下图进行选择,然后选择标准开发包,下载


20200824100729199.png


点击开发包然后开始下载,下载好之后解压文件。目录如下


20200824101024125.png


选中这7个文件,粘贴到你的项目中libs下面,这时候你的项目会报错,因为缺少依赖的jar包,所以要Sync,等待完成之后你的jar可以打开的时候,你的项目就不会报错了。


20200820162132445.png


然后Build → Clean Project 清除掉一些之前的配置


20200820163401869.png


现在运行一下,确保不影响我们之前的代码。


2020082016353225.png


OK,很明显没问题,那么就开始操作吧。


二、地图显示


首先打开你的Application,在onCreate中放入地图SDK初始化的代码


    //在使用SDK各组件之前初始化context信息,传入ApplicationContext
        SDKInitializer.initialize(this);
        //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
        //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
        SDKInitializer.setCoordType(CoordType.BD09LL);

20200820164352328.png


然后就可以来显示地图了,以我的性格,那肯定是新建一个页面来做这个的。在ui包下新建一个MapWeatherActivity,然后修改布局activity_map_weather.xml 代码如下:


<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.MapWeatherActivity">
  <!--地图控件-->
    <com.baidu.mapapi.map.MapView
        android:clickable="true"
        android:id="@+id/map_view"
        android:fitsSystemWindows="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>


地图有了,然后就是做沉浸式效果,打开MapWeatherActivity,修改代码如下:


package com.llw.goodweather.ui;
import android.os.Bundle;
import com.baidu.mapapi.map.MapView;
import com.llw.goodweather.R;
import com.llw.goodweather.utils.StatusBarUtil;
import com.llw.mvplibrary.base.BaseActivity;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
 * 地图天气
 */
public class MapWeatherActivity extends BaseActivity {
    @BindView(R.id.map_view)
    MapView mapView;//地图控件
    @Override
    public void initData(Bundle savedInstanceState) {
        StatusBarUtil.transparencyBar(context);//透明状态栏
        StatusBarUtil.StatusBarLightMode(context);//状态栏黑色字体
    }
    @Override
    public int getLayoutId() {
        return R.layout.activity_map_weather;
    }
}


可以看到这里继承了BaseActiivty,实现里面的两个构造方法,然后通过注解的方式绑定地图控件,在页面初始化initData()的时候修改状态栏的背景和字体颜色。在getLayoutId()中指定布局。

那么这里就先告一段落了,因为我是新建的页面,所以我需要到主页面MainActivity中找一个地方去进入这个地图页面MapWeatherActivity。就选择左上角了。

修改activity_main.xml中的布局


20200820173835693.png

20200820174048429.png


icon_map.png,尺寸是48*48,白色的所以你看不见,不过依然可以保存

2020082017565160.png


推荐一个图标网站,我APP上的图标基本都是在这个上面找的,真心不错。

iconfont


这个地图的图标也是在上面找的。可以看到右边已经有一个更多功能的按钮了,我在左边加一个地图的。图标作为按钮,右边的图标我也做了一些修改,看上面的图进行改动,触摸时会有一个半透明的背景,这个drawable代码如下:


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <solid android:color="#22000000"/>
            <corners android:radius="@dimen/dp_25"/>
        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="#00000000"/>
        </shape>
    </item>
</selector>


然后进入到MainActivity中


20200820175902872.png


点击跳转


20200820175936132.png


OK,运行看一下效果吧。说实话这个GIF大小上限5M真的很坑爹,最坑爹是我的GIF命名4.83M,结果还是告诉我超过限制,没有办法只能降低GIF的清晰度了。


20200820180628898.gif


可以看到不是很清晰,但是我也没办法呀。地图确实已经看到了,但是为什么是在北京呢?因为这是默认的初始位置,所以需要自己去定位到当前位置。


三、定位到当前所在位置


首先在MapWeatherActivity中增加一个定位的监听方法,实现BDLocationListener,代码如下:


  private LocationClient mLocationClient;//定位
    private BaiduMap mBaiduMap;//百度地图


  /**
     * 定位SDK监听,
     */
    private class MyLocationListener implements BDLocationListener {
        /**
         * 监听返回数据 MapView 销毁后不在处理新接收的位置
         * @param bdLocation 定位信息
         */
        @Override
        public void onReceiveLocation(BDLocation bdLocation) {
            if (bdLocation == null || mapView == null) {//做null处理,避免APP崩溃
                return;
            }
            MyLocationData locationData = new MyLocationData.Builder()//定位构造器
                    .accuracy(bdLocation.getRadius())//设置定位数据的精度信息,单位:米
                    .direction(bdLocation.getDirection())//设置定位数据的方向信息
                    .latitude(bdLocation.getLatitude())//设置定位数据的纬度
                    .longitude(bdLocation.getLongitude())//设置定位数据的经度
                    .build();//构建生成定位数据对象
            mBaiduMap.setMyLocationData(locationData);//设置定位数据,只有开启定位图层之后才会生效
            //创建一个经纬度构造对象,传入定位返回的经纬度,Latitude是纬度,Longitude是经度,一对经纬度值代表地球上一个地点。
            LatLng latLng = new LatLng(bdLocation.getLatitude(),bdLocation.getLongitude());
            MapStatus.Builder builder = new MapStatus.Builder()//创建地图状态构造器
                    .target(latLng)//设置地图中心点,传入经纬度对象
                    .zoom(13.0f);//设置地图缩放级别 13 表示  比例尺/2000米 2公里
            //改变地图状态,使用地图状态更新工厂中的新地图状态方法,传入状态构造器
            mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
        }
    }


在这个方法中,对定位做了监听和设置,然后启动定位。


最后只要在initData方法中调用就可以了。


20200821102747803.png


最后就是关于Activity的生命周期要对地图做相应的处理。代码如下:


  @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();//生命周期管理
    }
    @Override
    protected void onPause() {
        super.onPause();
        mapView.onPause();//生命周期管理
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLocationClient.stop();// 退出时销毁定位
        mBaiduMap.setMyLocationEnabled(false);// 关闭定位图层
        mapView.onDestroy();// 在activity执行onDestroy时必须调用mMapView.onDestroy()
    }


然后就可以运行了,运行看看吧。


20200821103400579.gif


可以看到定位还是蛮准的,定位时间取决于你的网速。当然如果你想要地址显示的更精确一些的话,可以修改


20200821103601585.png


可以参照这个表来进行设置


1665544697624.png


比如说我设置成4层级的


zoom(4.0f)


运行一下:


20200821105329987.png


根据自己的需求来就行了。所以我设置的是13,大概就能看清楚附近的区/县就可以了,因为和风天气API请求的最低单位就是区/县。


四、点击地图定位


当然光是一个当前定位是不足以满足用户的,用户一般是都是想点那里就点那里,你点了没反应就是你的软件有问题,然后直接给你卸载,你哭都没地方哭去。下面来看看具体实现吧。


先声明需要的变量


  private Marker marker;//标点也可以说是覆盖物
    private BitmapDescriptor bitmap;//标点的图标
    private double markerLatitude = 0;//标点纬度
    private double markerLongitude = 0;//标点经度
    private double latitude;//定位纬度
    private double longitude;//定位经度


刚才都说了是点击地图定位,那么肯定就需要一个点击事件对吧。当然这个事件肯定不是常规的View.OnClickListener,而是百度地图已经封装好的点击方法。


  /**
     * 初始化地图点击
     */
    private void initMapOnClick() {
        mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() {
            //地图内 Poi 单击事件回调函数  那么poi是什么呢?你可以当做兴趣点,
            // 比如我想知道我当前所在地有那些餐厅,那么餐厅就是poi,
            // 而你点击这个poi就会拿到详情的信息数据,当然不在我的业务需求之内,所以只做解释
            @Override
            public void onMapPoiClick(MapPoi mapPoi) {
            }
            //地图单击事件回调函数
            @Override
            public void onMapClick(LatLng latLng) {
            }
        });
    }


这里添加一个标点marker的图标


20200821113141354.png


可以看到要实现两个构造方法,而我只需要在onMapClick下处理点击之后的业务逻辑就可以了。


  //地图单击事件回调函数
  @Override
    public void onMapClick(LatLng latLng) {
       bitmap = BitmapDescriptorFactory.fromResource(R.mipmap.icon_marka);// 设置marker图标
       //通过LatLng获取经纬度
       markerLatitude = latLng.latitude;//获取纬度
       markerLongitude = latLng.longitude;//获取经度
       mBaiduMap.clear();//清除之前的图层
       MarkerOptions options = new MarkerOptions()//创建标点marker设置对象
               .position(latLng)//设置标点的定位
               .icon(bitmap);//设置标点图标
       marker = (Marker) mBaiduMap.addOverlay(options);//在地图上显示标点
       //点击地图之后重新定位
       initLocation();
    }


当点击地图时,或者经纬度,然后清除当前的图层,再配置标点的坐标和图标,然后添加到地图上,这时候重新定位一下,定位到标点的这个地方,所以要在监听的回调里面中修改原来的代码


20200821164447137.png


在拿到定位监听到之后首先判断是自动定位,还是点击地图定位。因为如果你点了地图,那么markerLatitude就不会是为0的,因为我在点击地图的时候给markerLatitude赋了值,作为判断条件区分你是自动还是手动。然后赋值给一个全局的经纬度变量,再把这个变量放到定位数据里,再设置成地图中心坐标,最后渲染出来,就可以做到,我点那里就定位到哪里了,指哪打哪。OK,没有效果图那就是扯淡,运行一下:


image.gif


效果还是不错滴!但是我又想回到原来的位置呢?


Wath!!!!

五、回到当前位置并清除标点


先来说一下实现的业务逻辑,当我一进入这个页面时,是自动定位的,这是要隐藏自动定位按钮,当我点击定位按钮时,清除标点回到当前定位地址。这个按钮我打算用浮动按钮来做,因为它隐藏和显示的时候会自带动画效果,相当不错。


在build.gradle中添加,有就不用了,然后Sync,否则你找不到这个控件。


implementation 'com.google.android.material:material:1.0.0'


简单修改activity_map_weather.xml


<com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/btn_auto_location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginLeft="@dimen/dp_50"
        android:layout_marginBottom="@dimen/dp_10"
        android:clickable="true"
        android:src="@mipmap/icon_auto_location"
        app:backgroundTint="@color/transparent_bg_3"
        app:backgroundTintMode="screen"
        app:borderWidth="@dimen/dp_0"
        app:fabSize="mini"
        app:hoveredFocusedTranslationZ="@dimen/dp_18"
        app:pressedTranslationZ="@dimen/dp_18"
        app:rippleColor="@color/blue_one" />


这个按钮会显示在页面的左下角比例尺的左边。


icon_auto_location.png如下,其他的参数都是常规数据,背景颜色尺寸一些都是可以自己写的。


20200824091142895.png


然后回到MapWeatherActivity

  @BindView(R.id.btn_auto_location)
    FloatingActionButton btnAutoLocation;//重新定位按钮


然后在点击的时候重置标点的经纬度参数值,清除标点,再重新定位


  /**
     * 点击事件
     */
    @OnClick(R.id.btn_auto_location)
    public void onViewClicked() {
        markerLatitude = 0;
        markerLongitude = 0;
        marker.remove();//清除标点
        initLocation();
    }


在定位成功的回调中对定位按钮进行显示和隐藏的控制。


20200824091853602.png


然后在新建一个initView方法,放入进入页面的一些基本配置。


20200824095049864.png


OK,运行一下。


image.gif


六、根据经纬度获取实际的定位信息


我们已经拿到经纬度信息了,那么这个信息需要转换为实际的位置,否则别人也不知道你定位在哪里,那就没有什么意义了。


先声明地址解析


private GeoCoder geoCoder;//百度地址解析


然后创建一个地址解析结果监听器


  /**
     * 编码结果监听
     */
    private OnGetGeoCoderResultListener onGetGeoCoderResultListener = new OnGetGeoCoderResultListener() {
        /**
         * 编码结果返回  就是通过具体位置信息获取坐标
         * @param geoCodeResult  编码返回结果
         */
        @Override
        public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
        }
        /**
         * 反编码结果返回  就是通过坐标获取具体位置信息
         * @param reverseGeoCodeResult 反编码返回结果
         */
        @Override
        public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
            if (reverseGeoCodeResult == null
                    || reverseGeoCodeResult.error != SearchResult.ERRORNO.NO_ERROR) {
                // 没有检测到结果
                return;
            }
            ReverseGeoCodeResult.AddressComponent addressDetail = reverseGeoCodeResult.getAddressDetail();
            //需要的地址信息就在AddressComponent 里
            ToastUtils.showShortToast(context,"地址信息:"+addressDetail.province+addressDetail.city+addressDetail.district+addressDetail.street);
            Log.d("dataStr",addressDetail.province+addressDetail.city+addressDetail.district+addressDetail.street);
        }
    };


然后在initView中赋值和添加监听


geoCoder = GeoCoder.newInstance();//赋值
geoCoder.setOnGetGeoCodeResultListener(onGetGeoCoderResultListener);//反编码结果监听

20200824111246102.png


最后就是在定位监听返回时获得坐标时,进行反编译


2020082411151611.png


运行一下:


20200824112723719.gif


OK,现在已经拿到相应的省市县数据了,那么就可以进行天气的数据渲染和请求了。请看下一篇文章



相关文章
|
1月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
139 0
安卓项目:app注册/登录界面设计
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
120 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
2月前
|
Java 测试技术 Android开发
Android性能测试——发现和定位内存泄露和卡顿
本文详细介绍了Android应用性能测试中的内存泄漏与卡顿问题及其解决方案。首先,文章描述了使用MAT工具定位内存泄漏的具体步骤,并通过实例展示了如何分析Histogram图表和Dominator Tree。接着,针对卡顿问题,文章探讨了其产生原因,并提供了多种测试方法,包括GPU呈现模式分析、FPS Meter软件测试、绘制圆点计数法及Android Studio自带的GPU监控功能。最后,文章给出了排查卡顿问题的四个方向,帮助开发者优化应用性能。
167 4
Android性能测试——发现和定位内存泄露和卡顿
|
2月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
158 2
|
2月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
102 3
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android应用开发中的多线程编程,涵盖基本概念、常见实现方式及最佳实践。主要内容包括主线程与工作线程的作用、多线程的多种实现方法(如 `Thread`、`HandlerThread`、`Executors` 和 Kotlin 协程),以及如何避免内存泄漏和合理使用线程池。通过有效的多线程管理,可以显著提升应用性能和用户体验。
69 10
|
1月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
216 0
|
2月前
|
XML 数据库 Android开发
10分钟手把手教你用Android手撸一个简易的个人记账App
该文章提供了使用Android Studio从零开始创建一个简单的个人记账应用的详细步骤,包括项目搭建、界面设计、数据库处理及各功能模块的实现方法。
|
3月前
|
API Android开发
Android P 性能优化:创建APP进程白名单,杀死白名单之外的进程
本文介绍了在Android P系统中通过创建应用进程白名单并杀死白名单之外的进程来优化性能的方法,包括设置权限、获取运行中的APP列表、配置白名单以及在应用启动时杀死非白名单进程的代码实现。
62 1
|
3月前
|
IDE Java 开发工具
探索安卓开发之旅:打造你的第一款App
【8月更文挑战第24天】在这篇文章中,我们将一起踏上激动人心的安卓开发之旅。不论你是编程新手还是希望扩展技能的老手,本文将为你提供一份详尽指南,帮助你理解安卓开发的基础知识并实现你的第一个应用程序。从搭建开发环境到编写“Hello World”,每一步都将用浅显易懂的语言进行解释。那么,让我们开始吧!

热门文章

最新文章