編輯:Android開發實例
先看下項目工程結構
ScaleView是比例尺控件,ZoomControlView是縮放控件,MainActivity就是我們的主界面了
先看下ZoomControlView類,代碼如下
- package com.example.baidumapdemo;
- import com.baidu.mapapi.map.MapView;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.widget.Button;
- import android.widget.RelativeLayout;
- import android.view.View.OnClickListener;
- public class ZoomControlView extends RelativeLayout implements OnClickListener{
- private Button mButtonZoomin;
- private Button mButtonZoomout;
- private MapView mapView;
- private int maxZoomLevel;
- private int minZoomLevel;
- public ZoomControlView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public ZoomControlView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init();
- }
- private void init() {
- View view = LayoutInflater.from(getContext()).inflate(R.layout.zoom_controls_layout, null);
- mButtonZoomin = (Button) view.findViewById(R.id.zoomin);
- mButtonZoomout = (Button) view.findViewById(R.id.zoomout);
- mButtonZoomin.setOnClickListener(this);
- mButtonZoomout.setOnClickListener(this);
- addView(view);
- }
- @Override
- public void onClick(View v) {
- if(mapView == null){
- throw new NullPointerException("you can call setMapView(MapView mapView) at first");
- }
- switch (v.getId()) {
- case R.id.zoomin:{
- mapView.getController().zoomIn();
- break;
- }
- case R.id.zoomout:{
- mapView.getController().zoomOut();
- break;
- }
- }
- }
- /**
- * 與MapView設置關聯
- * @param mapView
- */
- public void setMapView(MapView mapView) {
- this.mapView = mapView;
- // 獲取最大的縮放級別
- maxZoomLevel = mapView.getMaxZoomLevel();
- // 獲取最大的縮放級別
- minZoomLevel = mapView.getMinZoomLevel();
- }
- /**
- * 根據MapView的縮放級別更新縮放按鈕的狀態,當達到最大縮放級別,設置mButtonZoomin
- * 為不能點擊,反之設置mButtonZoomout
- * @param level
- */
- public void refreshZoomButtonStatus(int level){
- if(mapView == null){
- throw new NullPointerException("you can call setMapView(MapView mapView) at first");
- }
- if(level > minZoomLevel && level < maxZoomLevel){
- if(!mButtonZoomout.isEnabled()){
- mButtonZoomout.setEnabled(true);
- }
- if(!mButtonZoomin.isEnabled()){
- mButtonZoomin.setEnabled(true);
- }
- }
- else if(level == minZoomLevel ){
- mButtonZoomout.setEnabled(false);
- }
- else if(level == maxZoomLevel){
- mButtonZoomin.setEnabled(false);
- }
- }
- }
這個類封裝好了地圖的縮放功能,裡面主要是兩個按鈕,一個按鈕是放大MapView,當放大到了MapView的最大縮放級別,設置此按鈕的Enable為false,另一個按鈕縮小MapView,當縮小到了MapView最小的縮放級別,設置此按鈕的Enable為false,refreshZoomButtonStatus()方法就是實現了此功能,我們根據MapView的縮放級別來更新按鈕的狀態,我們還必須調用setMapView(MapView mapView)方法來設置ZoomControlView與MapView關聯,ZoomControlView的布局文件zoom_controls_layout我就不貼出來了,裡面就兩個按鈕,然後給按鈕設置背景選擇器seletor
ScaleView類的代碼如下
- package com.example.baidumapdemo;
- import com.baidu.mapapi.map.MapView;
- import com.baidu.platform.comapi.basestruct.GeoPoint;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.NinePatch;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.graphics.Typeface;
- import android.util.AttributeSet;
- import android.view.View;
- public class ScaleView extends View {
- private Paint mPaint;
- /**
- * 比例尺的寬度
- */
- private int scaleWidth;
- /**
- * 比例尺的高度
- */
- private int scaleHeight = 4;
- /**
- * 比例尺上面字體的顏色
- */
- private int textColor = Color.BLACK;
- /**
- * 比例尺上邊的字體
- */
- private String text;
- /**
- * 字體大小
- */
- private int textSize = 16;
- /**
- * 比例尺與字體間的距離
- */
- private int scaleSpaceText = 8;
- /**
- * 百度地圖最大縮放級別
- */
- private static final int MAX_LEVEL = 19;
- /**
- * 各級比例尺分母值數組
- */
- private static final int[] SCALES = {20, 50, 100, 200, 500, 1000, 2000,
- 5000, 10000, 20000, 25000, 50000, 100000, 200000, 500000, 1000000,
- 2000000 };
- /**
- * 各級比例尺上面的文字數組
- */
- private static final String[] SCALE_DESCS = { "20米", "50米", "100米", "200米",
- "500米", "1公裡", "2公裡", "5公裡", "10公裡", "20公裡", "25公裡", "50公裡",
- "100公裡", "200公裡", "500公裡", "1000公裡", "2000公裡" };
- private MapView mapView;
- /**
- * 與MapView設置關聯
- * @param mapView
- */
- public void setMapView(MapView mapView) {
- this.mapView = mapView;
- }
- public ScaleView(Context context) {
- this(context, null);
- }
- public ScaleView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public ScaleView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mPaint = new Paint();
- }
- /**
- * 繪制上面的文字和下面的比例尺,因為比例尺是.9.png,我們需要利用drawNinepath方法繪制比例尺
- */
- @SuppressLint("DrawAllocation")
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int width = scaleWidth;
- mPaint.setColor(textColor);
- mPaint.setAntiAlias(true);
- mPaint.setTextSize(textSize);
- mPaint.setTypeface(Typeface.DEFAULT_BOLD);
- float textWidth = mPaint.measureText(text);
- canvas.drawText(text, (width - textWidth) / 2, textSize, mPaint);
- Rect scaleRect = new Rect(0, textSize + scaleSpaceText, scaleWidth, textSize + scaleSpaceText + scaleHeight);
- drawNinepath(canvas, R.drawable.icon_scale, scaleRect);
- }
- /**
- * 手動繪制.9.png圖片
- * @param canvas
- * @param resId
- * @param rect
- */
- private void drawNinepath(Canvas canvas, int resId, Rect rect){
- Bitmap bmp= BitmapFactory.decodeResource(getResources(), resId);
- NinePatch patch = new NinePatch(bmp, bmp.getNinePatchChunk(), null);
- patch.draw(canvas, rect);
- }
- /**
- * 測量ScaleView的方法,
- */
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int widthSize = getWidthSize(widthMeasureSpec);
- int heightSize = getHeightSize(heightMeasureSpec);
- setMeasuredDimension(widthSize, heightSize);
- }
- /**
- * 測量ScaleView的寬度
- * @param widthMeasureSpec
- * @return
- */
- private int getWidthSize(int widthMeasureSpec){
- return MeasureSpec.getSize(widthMeasureSpec);
- }
- /**
- * 測量ScaleView的高度
- * @param widthMeasureSpec
- * @return
- */
- private int getHeightSize(int heightMeasureSpec){
- int mode = MeasureSpec.getMode(heightMeasureSpec);
- int height = 0;
- switch (mode) {
- case MeasureSpec.AT_MOST:
- height = textSize + scaleSpaceText + scaleHeight;
- break;
- case MeasureSpec.EXACTLY:{
- height = MeasureSpec.getSize(heightMeasureSpec);
- break;
- }
- case MeasureSpec.UNSPECIFIED:{
- height = Math.max(textSize + scaleSpaceText + scaleHeight, MeasureSpec.getSize(heightMeasureSpec));
- break;
- }
- }
- return height;
- }
- /**
- * 根據縮放級別,得到對應比例尺在SCALES數組中的位置(索引)
- * @param zoomLevel
- * @return
- */
- private static int getScaleIndex(int zoomLevel) {
- return MAX_LEVEL - zoomLevel;
- }
- /**
- * 根據縮放級別,得到對應比例尺
- *
- * @param zoomLevel
- * @return
- */
- public static int getScale(int zoomLevel) {
- return SCALES[getScaleIndex(zoomLevel)];
- }
- /**
- * 根據縮放級別,得到對應比例尺文字
- * @param zoomLevel
- * @return
- */
- public static String getScaleDesc(int zoomLevel) {
- return SCALE_DESCS[getScaleIndex(zoomLevel)];
- }
- /**
- * 根據地圖當前中心位置的緯度,當前比例尺,得出比例尺圖標應該顯示多長(多少像素)
- * @param map
- * @param scale
- * @return
- */
- public static int meterToPixels(MapView map, int scale) {
- // 得到當前中心位置對象
- GeoPoint geoPoint = map.getMapCenter();
- // 得到當前中心位置緯度
- double latitude = geoPoint.getLatitudeE6() / 1E6;
- // 得到象素數,比如當前比例尺是1/10000,比如scale=10000,對應在該緯度應在地圖中繪多少象素
- // 參考http://rainbow702.iteye.com/blog/1124244
- return (int) (map.getProjection().metersToEquatorPixels(scale) / (Math
- .cos(Math.toRadians(latitude))));
- }
- /**
- * 設置比例尺的寬度
- * @param scaleWidth
- */
- public void setScaleWidth(int scaleWidth) {
- this.scaleWidth = scaleWidth;
- }
- /**
- * 設置比例尺的上面的 text 例如 200公裡
- * @param text
- */
- private void setText(String text) {
- this.text = text;
- }
- /**
- * 設置字體大小
- * @param textSize
- */
- public void setTextSize(int textSize) {
- this.textSize = textSize;
- invalidate();
- }
- /**
- * 根據縮放級別更新ScaleView的文字以及比例尺的長度
- * @param level
- */
- public void refreshScaleView(int level) {
- if(mapView == null){
- throw new NullPointerException("you can call setMapView(MapView mapView) at first");
- }
- setText(getScaleDesc(level));
- setScaleWidth(meterToPixels(mapView, getScale(level)));
- invalidate();
- }
- }
ScaleView是比例尺控件類,主要是提供比例尺的繪制功能,在onDraw(Canvas canvas)的方法中繪制上面的距離和下面的比例尺長度,這裡面要說下drawNinepath()方法,因為我們的比例尺圖片是.9.png格式的,保證圖片拉伸狀態下不變形,如果用平常繪制一般圖片的方法會報ClassCastException,所以我們可以利用drawNinepath()來手動繪制.9.png格式的圖片,我們比例尺的長度是變化的,我們需要將以米為計量單位的距離(沿赤道)在當前縮放水平下轉換到一個以像素(水平)為計量單位的距離,meterToPixels()方法根據我們MapView當前的縮放級別,得出比例尺圖標應該顯示多長,refreshScaleView()是用來更新ScaleView的,更新上面的字符串和下面比例尺的長度,當然我們也必須調用setMapView(MapView mapView)方法來設置ScaleView與MapView關聯
接下來我們就來使用我們的比例尺控件和縮放控件了,先看下布局
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
- <com.baidu.mapapi.map.MapView
- android:id="@+id/bmapView"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:clickable="true" />
- <com.example.baidumapdemo.ZoomControlView
- android:id="@+id/ZoomControlView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:layout_marginBottom="20.0dip"
- android:layout_marginRight="5.0dip"/>
- <com.example.baidumapdemo.ScaleView
- android:id="@+id/scaleView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:layout_marginBottom="40dp"
- android:layout_marginLeft="20dp" />
- </RelativeLayout>
主界面MainActivity的代碼如下
- package com.example.baidumapdemo;
- import android.app.Activity;
- import android.graphics.Bitmap;
- import android.os.Bundle;
- import android.widget.Toast;
- import com.baidu.mapapi.BMapManager;
- import com.baidu.mapapi.MKGeneralListener;
- import com.baidu.mapapi.map.MKEvent;
- import com.baidu.mapapi.map.MKMapViewListener;
- import com.baidu.mapapi.map.MapController;
- import com.baidu.mapapi.map.MapPoi;
- import com.baidu.mapapi.map.MapView;
- import com.baidu.platform.comapi.basestruct.GeoPoint;
- public class MainActivity extends Activity{
- private BMapManager mBMapManager;
- /**
- * MapView 是地圖主控件
- */
- private MapView mMapView = null;
- /**
- * 用MapController完成地圖控制
- */
- private MapController mMapController = null;
- private ScaleView mScaleView;
- private ZoomControlView mZoomControlView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //使用地圖sdk前需先初始化BMapManager,這個必須在setContentView()先初始化
- mBMapManager = new BMapManager(this);
- //第一個參數是API key,
- //第二個參數是常用事件監聽,用來處理通常的網絡錯誤,授權驗證錯誤等,你也可以不添加這個回調接口
- mBMapManager.init("CC61ac7527b65c95899608810873b173", new MKGeneralListener() {
- //授權錯誤的時候調用的回調函數
- @Override
- public void onGetPermissionState(int iError) {
- if (iError == MKEvent.ERROR_PERMISSION_DENIED) {
- Toast.makeText(getApplication(), "API Key錯誤,請檢查!",
- Toast.LENGTH_LONG).show();
- }
- }
- //一些網絡狀態的錯誤處理回調函數
- @Override
- public void onGetNetworkState(int iError) {
- if (iError == MKEvent.ERROR_NETWORK_CONNECT) {
- Toast.makeText(getApplication(), "您的網絡出錯啦!",
- Toast.LENGTH_LONG).show();
- }
- }
- });
- setContentView(R.layout.activity_main);
- mMapView = (MapView) findViewById(R.id.bmapView);
- //隱藏自帶的地圖縮放控件
- mMapView.setBuiltInZoomControls(false);
- mScaleView = (ScaleView) findViewById(R.id.scaleView);
- mScaleView.setMapView(mMapView);
- mZoomControlView = (ZoomControlView) findViewById(R.id.ZoomControlView);
- mZoomControlView.setMapView(mMapView);
- //地圖顯示事件監聽器。 該接口監聽地圖顯示事件,用戶需要實現該接口以處理相應事件。
- mMapView.regMapViewListener(mBMapManager, new MKMapViewListener() {
- @Override
- public void onMapMoveFinish() {
- refreshScaleAndZoomControl();
- }
- @Override
- public void onMapLoadFinish() {
- }
- /**
- * 動畫結束時會回調此消息.我們在此方法裡面更新縮放按鈕的狀態
- */
- @Override
- public void onMapAnimationFinish() {
- refreshScaleAndZoomControl();
- }
- @Override
- public void onGetCurrentMap(Bitmap arg0) {
- }
- @Override
- public void onClickMapPoi(MapPoi arg0) {
- }
- });
- //獲取地圖控制器
- mMapController = mMapView.getController();
- //設置地圖是否響應點擊事件 .
- mMapController.enableClick(true);
- //設置地圖縮放級別
- mMapController.setZoom(14);
- refreshScaleAndZoomControl();
- //保存精度和緯度的類,
- GeoPoint p = new GeoPoint((int)(22.547923 * 1E6), (int)(114.067368 * 1E6));
- //設置p地方為中心點
- mMapController.setCenter(p);
- }
- private void refreshScaleAndZoomControl(){
- //更新縮放按鈕的狀態
- mZoomControlView.refreshZoomButtonStatus(Math.round(mMapView.getZoomLevel()));
- mScaleView.refreshScaleView(Math.round(mMapView.getZoomLevel()));
- }
- @Override
- protected void onResume() {
- //MapView的生命周期與Activity同步,當activity掛起時需調用MapView.onPause()
- mMapView.onResume();
- super.onResume();
- }
- @Override
- protected void onPause() {
- //MapView的生命周期與Activity同步,當activity掛起時需調用MapView.onPause()
- mMapView.onPause();
- super.onPause();
- }
- @Override
- protected void onDestroy() {
- //MapView的生命周期與Activity同步,當activity銷毀時需調用MapView.destroy()
- mMapView.destroy();
- //退出應用調用BMapManager的destroy()方法
- if(mBMapManager != null){
- mBMapManager.destroy();
- mBMapManager = null;
- }
- super.onDestroy();
- }
- }
主界面的代碼還是比較簡單的,主要是利用MapView的regMapViewListener()來注冊地圖顯示事件監聽器。 該接口監聽地圖顯示事件,用戶需要實現該接口以處理相應事件,分別在回調方法onMapAnimationFinish()和onMapMoveFinish()來更新ZoomControlView和ScaleView的一些狀態
在運行之前需要在Manifest中加入相對應的權限問題
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
運行結果
源碼下載
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
首先來看一下使用Java語言編寫的Android應用程序從源碼到安裝包的整個過程,示意圖如下,其中包含編譯、鏈接和簽名等: (1)使用aapt工具生成R.jav