面向GIS的Android studio移动开发(一)--在地图上绘制一些具有基本信息的图形

学了这么久的Android studio的开发,作者都快忘了自己的专业是GIS了,碰巧最近在搞一些GIS的开发大赛,正好学习一些GIS+Android的开发,今天也是有所收获,在此记录一下

前置条件

学习GIS的都知道,我们的开发都离不开地图的利用,所以我们首先要学会如何去调用地图,这里我们用高德地图来进行一个示范:这里是要做好的准备,在这两个文章中都有所介绍:
Android studio申请高德(百度)地图key
Android studio进阶教程之(二)–如何导入高德地图

在做完这一切之后,我们就可以进行对地图的开发了

一、控件的交互

1.放大与缩小

在我们的之前的代码中其实已经把这个功能已经做出来了:
请添加图片描述

private void initializeMap() {
        if (aMap == null) {
            aMap = mMapView.getMap();

            // 设置信息窗口适配器
            aMap.setInfoWindowAdapter(this);
            // 设置Marker点击监听器
            aMap.setOnMarkerClickListener(this);

            // 初始地图位置和缩放级别
            aMap.animateCamera(CameraUpdateFactory.zoomTo(16));
            aMap.getUiSettings().setScaleControlsEnabled(true);
        }
    }

官方的定位是这样的:


private UiSettings mUiSettings;//定义一个UiSettings对象
mUiSettings = aMap.getUiSettings();//实例化UiSettings类对象

setZoomControlsEnabled(boolean b);//缩放按钮

2.指南针


setCompassEnabled(boolean b);


3.定位按钮


aMap.setLocationSource(this);//通过aMap对象设置定位数据源的监听

mUiSettings.setMyLocationButtonEnabled(true); //显示默认的定位按钮

aMap.setMyLocationEnabled(true);// 可触发定位并显示当前位置


4.比例尺与LOGO

setScaleControlsEnabled(boolean b);//控制比例尺控件是否显示
setLogoPosition(int position);//设置logo位置

这些都是地图应该所应有的属性,这里就不再过多赘述。

二、在地图上绘制图形

1.绘制点并包含信息

这个应该是每个GIS开发者都应该会的东西,地理信息没有信息怎么能行,所以一个包含信息的点就非常重要。
地图 SDK 提供的点标记功能包含两大部分,一部分是点(俗称 Marker)、另一部分是浮于点上方的信息窗体(俗称 InfoWindow)。
所以我们今天就以两个功能进行设计
官方代码如下:
绘制 Marker 的代码如下:

LatLng latLng = new LatLng(39.906901,116.397972);
final Marker marker = aMap.addMarker(new MarkerOptions().position(latLng).title("北京").snippet("DefaultMarker"));

绘制自定义 Marker:

MarkerOptions markerOption = new MarkerOptions();
    markerOption.position(Constants.XIAN);
    markerOption.title("西安市").snippet("西安市:34.341568, 108.940174");

    markerOption.draggable(true);//设置Marker可拖动
    markerOption.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
        .decodeResource(getResources(),R.drawable.location_marker)));
    // 将Marker设置为贴地显示,可以双指下拉地图查看效果
    markerOption.setFlat(true);//设置marker平贴地图效果

Marker 点击事件

点击 Marker 时会回调AMap.OnMarkerClickListener,监听器的实现示例如下:

// 定义 Marker 点击事件监听
AMap.OnMarkerClickListener markerClickListener = new AMap.OnMarkerClickListener() {
    // marker 对象被点击时回调的接口
    // 返回 true 则表示接口已响应事件,否则返回false
    @Override
    public boolean onMarkerClick(Marker marker) {
        return false;
    }
};
// 绑定 Marker 被点击事件
mAMap.setOnMarkerClickListener(markerClickListener);

实现 InfoWindowAdapter
InfoWindowAdapter是一个接口,其中有两个方法需要实现,依次来看一下:

public interface InfoWindowAdapter {
        View getInfoWindow(Marker marker);
        View getInfoContents(Marker marker);
}

InfoWindow 点击事件

点击 InfoWindow 时会回调 AMap.OnInfoWindowClickListener,监听器的实现示例如下:

OnInfoWindowClickListener listener = new OnInfoWindowClickListener() {
 
    @Override
    public void onInfoWindowClick(Marker arg0) {
        
        arg0.setTitle("infowindow clicked");
    }
};
//绑定信息窗点击事件
aMap.setOnInfoWindowClickListener(listener);

至此,我们的基础性质就已经学完了,接下来我们进行实战:
主体代码:

private void addMarker(double lat, double lng, String title, String phone) {
        LatLng position = new LatLng(lat, lng);
        aMap.addMarker(new MarkerOptions()
                .position(position)
                .title(title)
                .snippet("售卖商品: " + phone)
                .draggable(false));
    }

    // 实现信息窗口布局
    @Override
    public View getInfoWindow(Marker marker) {
        View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_window, null);
        renderInfoWindow(marker, infoWindow);
        return infoWindow;
    }

    @Override
    public View getInfoContents(Marker marker) {
        return null; // 使用默认信息窗口背景时返回null
    }

    private void renderInfoWindow(Marker marker, View view) {
        TextView title = view.findViewById(R.id.info_window_title);
        TextView content = view.findViewById(R.id.info_window_content);

        title.setText(marker.getTitle());
        content.setText(marker.getSnippet());
    }

    // 处理Marker点击事件
    @Override
    public boolean onMarkerClick(Marker marker) {
        // 显示信息窗口(第二个参数为是否强制使用默认布局)
        marker.showInfoWindow();
        return true; // 消费点击事件
    }

添加信息:

private void addMarkers() {
        // 使用自定义方法创建带数据的Marker
        addMarker(28.711666, 115.826600, "AAA水果批发商小王", "苹果");
        addMarker(28.711667, 115.826750, "AAA水果批发商小李", "芒果");
        addMarker(28.711680, 115.826450, "AAA水果批发商小张", "草莓");
        // 东北地区
        addMarker(45.8038, 126.5340, "哈尔滨水果批发商老刘", "蓝莓"); // 黑龙江哈尔滨
        addMarker(43.8171, 125.3235, "长春水果批发商孙姐", "人参果"); // 吉林长春
        addMarker(41.8354, 123.4299, "沈阳水果批发商老金", "南果梨"); // 辽宁沈阳

        // 华北地区
        addMarker(39.9042, 116.4074, "北京新发地批发市场", "平谷大桃"); // 北京
        addMarker(37.8706, 112.5489, "太原水果批发商老陈", "沙金红杏"); // 山西太原
        addMarker(38.0428, 114.5149, "石家庄水果批发商赵总", "赞皇大枣"); // 河北石家庄

        // 华东地区
        addMarker(31.2304, 121.4737, "上海西郊国际批发", "南汇水蜜桃"); // 上海
        addMarker(30.2595, 120.2194, "杭州水果批发商王姐", "塘栖枇杷"); // 浙江杭州
        addMarker(32.0603, 118.7969, "南京众彩批发市场", "固城湖螃蟹"); // 江苏南京
        addMarker(36.6512, 117.1201, "济南堤口批发市场", "烟台樱桃"); // 山东济南

        // 华中地区
        addMarker(30.5951, 114.2999, "武汉光霞果批市场", "梁子湖螃蟹"); // 湖北武汉
        addMarker(28.1941, 112.9723, "长沙红星批发市场", "炎陵黄桃"); // 湖南长沙
        addMarker(34.7473, 113.6253, "郑州万邦物流城", "灵宝苹果"); // 河南郑州

        // 华南地区
        addMarker(23.1291, 113.2644, "广州江南果菜市场", "增城荔枝"); // 广东广州
        addMarker(20.0444, 110.1999, "海口南北水果市场", "文昌椰子"); // 海南海口
        addMarker(22.8176, 108.3663, "南宁海吉星市场", "百色芒果"); // 广西南宁

        // 西北地区
        addMarker(34.3416, 108.9398, "西安雨润批发市场", "周至猕猴桃"); // 陕西西安
        addMarker(36.0611, 103.8343, "兰州大青山市场", "白兰瓜"); // 甘肃兰州
        addMarker(43.8256, 87.6168, "乌鲁木齐九鼎市场", "哈密瓜"); // 新疆乌鲁木齐

        // 西南地区
        addMarker(29.6535, 91.1705, "拉萨药王山市场", "林芝苹果"); // 西藏拉萨
        addMarker(25.0433, 102.7062, "昆明金马正昌市场", "蒙自石榴"); // 云南昆明
        addMarker(26.6470, 106.6302, "贵阳石板哨市场", "修文猕猴桃"); // 贵州贵阳
        addMarker(30.5728, 104.0668, "成都濛阳农批市场", "攀枝花芒果"); // 四川成都

        // 特别行政区
        addMarker(22.3193, 114.1694, "香港长沙湾市场", "菲律宾香蕉"); // 香港
        addMarker(22.1987, 113.5439, "澳门提督马路市场", "台湾莲雾"); // 澳门

    }

全部代码:

package com.example.gdmap;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.MapView;
import com.amap.api.maps.MapsInitializer;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.MyLocationStyle;

public class MapActivity extends AppCompatActivity implements
        AMap.OnMarkerClickListener,
        AMap.InfoWindowAdapter {

    private MapView mMapView;
    private AMap aMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);

        // 初始化地图
        MapsInitializer.updatePrivacyShow(this, true, true);
        MapsInitializer.updatePrivacyAgree(this, true);
        mMapView = findViewById(R.id.map);
        mMapView.onCreate(savedInstanceState);

        initializeMap();
        setupLocationStyle();
        addMarkers();
    }

    private void initializeMap() {
        if (aMap == null) {
            aMap = mMapView.getMap();

            // 设置信息窗口适配器
            aMap.setInfoWindowAdapter(this);
            // 设置Marker点击监听器
            aMap.setOnMarkerClickListener(this);

            // 初始地图位置和缩放级别
            aMap.animateCamera(CameraUpdateFactory.zoomTo(16));
            aMap.getUiSettings().setScaleControlsEnabled(true);
        }
    }

    private void setupLocationStyle() {
        MyLocationStyle myLocationStyle = new MyLocationStyle();
        myLocationStyle.interval(6000);
        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_SHOW);
        aMap.setMyLocationStyle(myLocationStyle);
        aMap.setMyLocationEnabled(true);
    }

    private void addMarkers() {
        // 使用自定义方法创建带数据的Marker
        addMarker(28.711666, 115.826600, "AAA水果批发商小王", "苹果");
        addMarker(28.711667, 115.826750, "AAA水果批发商小李", "芒果");
        addMarker(28.711680, 115.826450, "AAA水果批发商小张", "草莓");
        // 东北地区
        addMarker(45.8038, 126.5340, "哈尔滨水果批发商老刘", "蓝莓"); // 黑龙江哈尔滨
        addMarker(43.8171, 125.3235, "长春水果批发商孙姐", "人参果"); // 吉林长春
        addMarker(41.8354, 123.4299, "沈阳水果批发商老金", "南果梨"); // 辽宁沈阳

        // 华北地区
        addMarker(39.9042, 116.4074, "北京新发地批发市场", "平谷大桃"); // 北京
        addMarker(37.8706, 112.5489, "太原水果批发商老陈", "沙金红杏"); // 山西太原
        addMarker(38.0428, 114.5149, "石家庄水果批发商赵总", "赞皇大枣"); // 河北石家庄

        // 华东地区
        addMarker(31.2304, 121.4737, "上海西郊国际批发", "南汇水蜜桃"); // 上海
        addMarker(30.2595, 120.2194, "杭州水果批发商王姐", "塘栖枇杷"); // 浙江杭州
        addMarker(32.0603, 118.7969, "南京众彩批发市场", "固城湖螃蟹"); // 江苏南京
        addMarker(36.6512, 117.1201, "济南堤口批发市场", "烟台樱桃"); // 山东济南

        // 华中地区
        addMarker(30.5951, 114.2999, "武汉光霞果批市场", "梁子湖螃蟹"); // 湖北武汉
        addMarker(28.1941, 112.9723, "长沙红星批发市场", "炎陵黄桃"); // 湖南长沙
        addMarker(34.7473, 113.6253, "郑州万邦物流城", "灵宝苹果"); // 河南郑州

        // 华南地区
        addMarker(23.1291, 113.2644, "广州江南果菜市场", "增城荔枝"); // 广东广州
        addMarker(20.0444, 110.1999, "海口南北水果市场", "文昌椰子"); // 海南海口
        addMarker(22.8176, 108.3663, "南宁海吉星市场", "百色芒果"); // 广西南宁

        // 西北地区
        addMarker(34.3416, 108.9398, "西安雨润批发市场", "周至猕猴桃"); // 陕西西安
        addMarker(36.0611, 103.8343, "兰州大青山市场", "白兰瓜"); // 甘肃兰州
        addMarker(43.8256, 87.6168, "乌鲁木齐九鼎市场", "哈密瓜"); // 新疆乌鲁木齐

        // 西南地区
        addMarker(29.6535, 91.1705, "拉萨药王山市场", "林芝苹果"); // 西藏拉萨
        addMarker(25.0433, 102.7062, "昆明金马正昌市场", "蒙自石榴"); // 云南昆明
        addMarker(26.6470, 106.6302, "贵阳石板哨市场", "修文猕猴桃"); // 贵州贵阳
        addMarker(30.5728, 104.0668, "成都濛阳农批市场", "攀枝花芒果"); // 四川成都

        // 特别行政区
        addMarker(22.3193, 114.1694, "香港长沙湾市场", "菲律宾香蕉"); // 香港
        addMarker(22.1987, 113.5439, "澳门提督马路市场", "台湾莲雾"); // 澳门

    }

    private void addMarker(double lat, double lng, String title, String phone) {
        LatLng position = new LatLng(lat, lng);
        aMap.addMarker(new MarkerOptions()
                .position(position)
                .title(title)
                .snippet("售卖商品: " + phone)
                .draggable(false));
    }

    // 实现信息窗口布局
    @Override
    public View getInfoWindow(Marker marker) {
        View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_window, null);
        renderInfoWindow(marker, infoWindow);
        return infoWindow;
    }

    @Override
    public View getInfoContents(Marker marker) {
        return null; // 使用默认信息窗口背景时返回null
    }

    private void renderInfoWindow(Marker marker, View view) {
        TextView title = view.findViewById(R.id.info_window_title);
        TextView content = view.findViewById(R.id.info_window_content);

        title.setText(marker.getTitle());
        content.setText(marker.getSnippet());
    }

    // 处理Marker点击事件
    @Override
    public boolean onMarkerClick(Marker marker) {
        // 显示信息窗口(第二个参数为是否强制使用默认布局)
        marker.showInfoWindow();
        return true; // 消费点击事件
    }

    // 生命周期方法
    @Override
    protected void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mMapView.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMapView.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mMapView.onSaveInstanceState(outState);
    }
}

信息的背景样式:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#FFFFFF"/>
    <stroke
        android:width="1dp"
        android:color="#CCCCCC"/>
    <corners
        android:radius="8dp"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="250dp"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="12dp"
    android:background="@drawable/info_window_bg">

    <TextView
        android:id="@+id/info_window_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textColor="#333"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/info_window_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:textSize="14sp"
        android:textColor="#666"/>

</LinearLayout>

效果图:
请添加图片描述
这样我们就在地图中插入了带有信息的点了。

2.在地图中划线

后面的部分在GIS中就没有很常用了,所以我在这里把示例代码给出,读者可以自行实现:


List<LatLng> latLngs = new ArrayList<LatLng>();
latLngs.add(new LatLng(39.999391,116.135972));
latLngs.add(new LatLng(39.898323,116.057694));
latLngs.add(new LatLng(39.900430,116.265061));
latLngs.add(new LatLng(39.955192,116.140092));
polyline =AMap.addPolyline(new PolylineOptions().
        addAll(latLngs).width(10).color(Color.argb(255, 1, 1, 1)));


3.绘制多边形

画圆:


LatLng latLng = new LatLng(39.984059,116.307771);
circle = AMap.addCircle(new CircleOptions().
        center(latLng).
        radius(1000).
        fillColor(Color.argb(progress, 1, 1, 1)).
        strokeColor(Color.argb(progress, 1, 1, 1)).
        strokeWidth(15));

椭圆:

aMap.addPolygon(new PolygonOptions()
                .addAll(createRectangle( new LatLng(31.238068, 121.501654), 1, 1))
                .fillColor(Color.LTGRAY).strokeColor(Color.RED).strokeWidth(1));
        PolygonOptions options = new PolygonOptions();
        int numPoints = 400;
        float semiHorizontalAxis = 5f;
        float semiVerticalAxis = 2.5f;
        double phase = 2 * Math.PI / numPoints;
        for (int i = 0; i <= numPoints; i++) {
            options.add(new LatLng(Constants.BEIJING.latitude
                    + semiVerticalAxis * Math.sin(i * phase),
                    Constants.BEIJING.longitude + semiHorizontalAxis
                            * Math.cos(i * phase)));
        }
        // 绘制一个椭圆
        polygon = aMap.addPolygon(options.strokeWidth(25)
                .strokeColor(Color.argb(50, 1, 1, 1))
                .fillColor(Color.argb(50, 1, 1, 1)));
    }

绘制长方形及其四个角

/**
   * 生成一个长方形的四个坐标点
   */
  private List<LatLng> createRectangle(LatLng center, double halfWidth,
      double halfHeight) {
    List<LatLng> latLngs = new ArrayList<LatLng>();
    latLngs.add(new LatLng(center.latitude - halfHeight, center.longitude - halfWidth));
    latLngs.add(new LatLng(center.latitude - halfHeight, center.longitude + halfWidth));
    latLngs.add(new LatLng(center.latitude + halfHeight, center.longitude + halfWidth));
    latLngs.add(new LatLng(center.latitude + halfHeight, center.longitude - halfWidth));
    return latLngs;
  }
}

// 绘制一个长方形
aMap.addPolygon(new PolygonOptions()
.addAll(createRectangle(Constants.SHANGHAI, 1, 1))
.fillColor(Color.LTGRAY).strokeColor(Color.RED).strokeWidth(1));


绘制多边形,以S形状为例:


// 定义多边形的5个点点坐标
LatLng latLng1 = new LatLng(42.742467, 79.842785);
LatLng latLng2 = new LatLng(43.893433, 98.124035);
LatLng latLng3 = new LatLng(33.058738, 101.463879);
LatLng latLng4 = new LatLng(25.873426, 95.838879);
LatLng latLng5 = new LatLng(30.8214661, 78.788097);

// 声明 多边形参数对象
PolygonOptions polygonOptions = new PolygonOptions();
// 添加 多边形的每个顶点(顺序添加)
polygonOptions.add(latLng1, latLng2, latLng3, latLng4, latLng5);
polygonOptions.strokeWidth(15) // 多边形的边框
.strokeColor(Color.argb(50, 1, 1, 1)) // 边框颜色
.fillColor(Color.argb(1, 1, 1, 1));   // 多边形的填充色

尾言

这次主要面向为学习GIS相关专业的移动开发的读者,因为本人也是这一方面专业的,未来也会不断将Android与GIS相结合,比如arcgis,supermap,postgis等,敬请期待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隐-梵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值