編輯:關於Android編程
4、配置AndroidMainfest.xml文件:
< uses-permission android:name ="android.permission.ACCESS_NETWORK_STATE" />
注:上面的權限是我的項目中所有用到的權限,具體可參考百度地圖和定位地圖所需要的權限。 還需要配置地圖的AK以及定位service:
< meta-data android:name= "com.baidu.lbsapi.API_KEY" android:value= "API控制台申請到的AK" /> < service android:name= "com.baidu.location.f" android:enabled= "true" android:process= ":remote" >5、在Application中初始化地圖SDK SDKInitializer.initialize(getApplicationContext());
import com.baidu.location.BDLocation; import com.baidu.location.BDLocationListener; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.baidu.location.LocationClientOption.LocationMode; import com.lb.baidumapdemo.db.DBConstants; import com.lb.baidumapdemo.db.ShareDB; import com.lb.baidumapdemo.face.LocationFace; import android.content.Context; /** * @ClassName: LocationFaceUtil * @Description: 定位幫助類,這個類只用來做定位用 * @author libiao * @date 2015 -8 -20 下午2:48:07 * */ public class LocationFaceUtil implements BDLocationListener { private LocationFace locationFace; // 這個為自己寫的一個接口,用來回調給外部處理 public LocationClient mLocationClient = null; private Context context; public LocationFaceUtil(Context context, LocationFace locationFace) { super(); this. locationFace = locationFace; this. context = context; mLocationClient = new LocationClient(context); mLocationClient.registerLocationListener(LocationFaceUtil. this); startLocation(); } private void startLocation() { LocationClientOption option = new LocationClientOption(); option.setLocationMode(LocationMode. Hight_Accuracy); // 可選,默認高精度,設置定位模式,高精度,低功耗,僅設備 option.setCoorType( "bd09ll"); // 可選,默認gcj02,設置返回的定位結果坐標系 option.setScanSpan(0); // 可選,默認0,即僅定位一次,設置發起定位請求的間隔需要大於等於1000ms才是有效的 option.setIsNeedAddress( true); // 可選,設置是否需要地址信息,默認不需要 option.setOpenGps( true); // 可選,默認false,設置是否使用 gps option.setLocationNotify( true); // 可選,默認false,設置是否當 gps有效時按照1S1次頻率輸出GPS結果 option.setIsNeedLocationDescribe( true); // 可選,默認false,設置是否需要位置語義化結果,可以在BDLocation.getLocationDescribe裡得到,結果類似於“在北京天安門附近” option.setIsNeedLocationPoiList( true); // 可選,默認false,設置是否需要POI結果,可以在BDLocation.getPoiList裡得到 option.setIgnoreKillProcess( false); // 可選,默認false,定位SDK內部是一個SERVICE,並放到了獨立進程,設置是否在stop的時候殺死這個進程,默認殺死 option.SetIgnoreCacheException( false); // 可選,默認false,設置是否收集CRASH信息,默認收集 option.setEnableSimulateGps( false); // 可選,默認false,設置是否需要過濾 gps仿真結果,默認需要 mLocationClient.setLocOption(option); mLocationClient.start(); } @Override public void onReceiveLocation(BDLocation arg0) { //注意這裡,一定要判斷BdLocation的返回值,只有在getLocType()==61或者161的情況下才表示定位成功,具體返回的錯誤碼可參考http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/ermsg if (arg0.getLocType() == 61 || arg0.getLocType() == 161 && arg0.getLatitude() != 0.0) { //將城市的名字存到SharedPreferences裡面 new ShareDB( context).save(DBConstants. CITY_NAME, arg0.getCity()); //將定位結果回調給locationFace的locationResult()方法 locationFace.locationResult(arg0); } } }
new LocationFaceUtil(getApplicationContext(), new LocationFace() { @Override public void locationResult(BDLocation location) { bdLocation = location; addMarker(); } });然後回調的信息就全部在這個bdLocation裡面了,接著標注當前自己的位置,就是調用的addMarker()方法 下面代碼中的:mBaiduMap=(MapView) findViewById(R.id.basemap).getMap();
private void addMarker() { // 設置地圖類型 MAP_TYPE_NORMAL 普通圖; MAP_TYPE_SATELLITE 衛星圖 mBaiduMap.setMapType(BaiduMap. MAP_TYPE_NORMAL); // 開啟交通圖 mBaiduMap.setTrafficEnabled( true); // 設置地圖當前級別 MapStatusUpdate statusUpdate = MapStatusUpdateFactory.zoomTo(19); mBaiduMap.setMapStatus(statusUpdate); // 構建覆蓋物的經緯度 LatLng latLng = new LatLng( bdLocation.getLatitude(), bdLocation.getLongitude()); //覆蓋物顯示的圖標 BitmapDescriptor descriptor = BitmapDescriptorFactory.fromResource(R.drawable. icon_gcoding); OverlayOptions option = new MarkerOptions().position(latLng).icon(descriptor).draggable(true); // 清除地圖上所有的覆蓋物 mBaiduMap.clear(); // 將覆蓋物添加到地圖上 mBaiduMap.addOverlay(option); // 將覆蓋物設置為地圖中心 MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(latLng); // 以動畫方式更新地圖狀態,動畫耗時 300 ms mBaiduMap.animateMapStatus(u); mBaiduMap.setOnMarkerClickListener(BaseMapActivity. this); mBaiduMap.setOnMarkerDragListener(BaseMapActivity. this); }
import android.graphics.Point; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; import android.widget.Toast; import com.baidu.mapapi.map.BaiduMap; import com.baidu.mapapi.map.BaiduMap.OnMapClickListener; import com.baidu.mapapi.map.BaiduMap.OnMarkerClickListener; import com.baidu.mapapi.map.BitmapDescriptor; import com.baidu.mapapi.map.BitmapDescriptorFactory; import com.baidu.mapapi.map.InfoWindow; import com.baidu.mapapi.map.MapPoi; import com.baidu.mapapi.map.MapStatusUpdate; import com.baidu.mapapi.map.MapStatusUpdateFactory; import com.baidu.mapapi.map.MapView; import com.baidu.mapapi.map.Marker; import com.baidu.mapapi.map.MarkerOptions; import com.baidu.mapapi.map.OverlayOptions; import com.baidu.mapapi.model.LatLng; import com.lb.baidumapdemo.R; import com.lb.baidumapdemo.base.BaseActivity; public class MarkerMapActivity extends BaseActivity implements OnMarkerClickListener,OnMapClickListener { private MapView mBaiduMapView; // 地圖界面 private BaiduMap mBaiduMap; // 地圖的管理類 private String[] titles = new String[] { "one", "two", "three", "four" };//這是是四個坐標對應的四個信息 //要放在地圖上的四個坐標 private LatLng[] latlngs = new LatLng[] { new LatLng(22.539895,114.058935), new LatLng(22.540729,114.066337), new LatLng(22.543763,114.06458), new LatLng(22.538614,114.062811) }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout. activity_markermap); mBaiduMapView = (MapView) findViewById(R.id. markermap); mBaiduMap = mBaiduMapView.getMap(); //設置地圖點擊事件 mBaiduMap.setOnMapClickListener( this); initMarker(); } private void initMarker() { mBaiduMap.clear(); LatLng latLng = null; OverlayOptions overlayOptions = null; // 設置地圖類型 MAP_TYPE_NORMAL 普通圖; MAP_TYPE_SATELLITE 衛星圖 mBaiduMap.setMapType(BaiduMap. MAP_TYPE_NORMAL); // 開啟交通圖 mBaiduMap.setTrafficEnabled( true); MapStatusUpdate statusUpdate = MapStatusUpdateFactory.zoomTo(17); mBaiduMap.setMapStatus(statusUpdate); BitmapDescriptor descriptor = BitmapDescriptorFactory.fromResource(R.drawable. icon_gcoding); //循環添加四個覆蓋物到地圖上 for ( int i = 0; i < titles. length; i++) { latLng= latlngs[i]; overlayOptions = new MarkerOptions().position(latLng).icon(descriptor); // 將覆蓋物添加到地圖上 Marker marker=(Marker) mBaiduMap.addOverlay(overlayOptions); Bundle bundle = new Bundle(); bundle.putString( "info", titles[i]+ "個"); marker.setExtraInfo(bundle); } // 將最後一個坐標設置為地圖中心 MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(latLng); mBaiduMap.setMapStatus(u); //設置地圖覆蓋物的點擊事件 mBaiduMap.setOnMarkerClickListener(MarkerMapActivity. this); } /** * @Title: onMarkerClick * @Description: 覆蓋物點擊事件,每次點擊一個覆蓋物則會在相應的覆蓋物上顯示一個InfoWindow * @param marker * @return */ @Override public boolean onMarkerClick(Marker marker) { final String msg = marker.getExtraInfo().getString( "info"); InfoWindow mInfoWindow; // 生成一個TextView用戶在地圖中顯示InfoWindow TextView location = new TextView(getApplicationContext()); location.setBackgroundResource(R.drawable. shape_popup); location.setPadding(30, 20, 30, 20); location.setText(msg); //構建彈框所在的經緯度, final LatLng ll = marker.getPosition(); Point p = mBaiduMap.getProjection().toScreenLocation(ll); p. y -= 47; //讓彈框在Y軸偏移47 LatLng llInfo = mBaiduMap.getProjection().fromScreenLocation(p); //根據上面配置好的參數信息,構造一個InfoWindow。 mInfoWindow = new InfoWindow(location, llInfo, -47); //構建好之後,然後調用show的方法,讓彈框顯示出來 mBaiduMap.showInfoWindow(mInfoWindow); //彈框點擊事件- location.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { Toast. makeText(MarkerMapActivity.this, msg, Toast.LENGTH_SHORT).show(); } }); return true; } /** * @Title: onMapClick * @Description: 地圖點擊事件,點擊地圖的時候要讓InfoWindow消失 * @param arg0 */ @Override public void onMapClick(LatLng arg0) { mBaiduMap.hideInfoWindow(); } /** * @Title: onMapPoiClick * @Description: 興趣點點擊事件 * @param arg0 * @return */ @Override public boolean onMapPoiClick(MapPoi arg0) { return false; } }3:坐標地址互相換算 在很多請求當中只會返回經緯度的坐標,並不會返回具體的信息,這個時候需要用到坐標換算成地址。 坐標反轉類:GeoCoder類,我們可以看一下這個類的方法:
private GeoCoder geoCoder; // 經緯度地理位置坐標反轉類 geoCoder = GeoCoder. newInstance(); geoCoder.setOnGetGeoCodeResultListener( this); // 設置反地理查詢監聽器 geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(arg0.getPosition()));這裡是根據經緯度來獲取地址信息 然後在下面的方法裡面回調:
/** * @Title: onGetGeoCodeResult * @Description: 坐標換算 根據地址得到坐標 * @param arg0 */ @Override public void onGetGeoCodeResult(GeoCodeResult arg0) { } /** * @Title: onGetReverseGeoCodeResult * @Description: 坐標換算,根據坐標得到地質 * @param arg0 */ @Override public void onGetReverseGeoCodeResult(ReverseGeoCodeResult arg0) { //根據上面的請求之後,回調會進入到這個方法裡面來,然後在所有的地址信息在ReverseGeoCodeResult 當中 }4:POI興趣點檢索 1、初始化PoiSearch類,構造檢索的參數 檢索,可以分為四種類型的檢索,根據我們自己不同的需求,需要調用不同的方法,並傳入不同的參數
這裡我們先看一下范圍內檢索:searchInBound(PoiBoundSearchOptionoption) PoiBoundSearchOption類,他有四個方法,入下圖所示,這裡的pageNum是從0開始的! 在設置pageCapacity的時候,我在測試的過程中最大是50條,超過50默認就返回了10條(這個版本的是50),其他的參數就不多說了。 其他的三個檢索的方法,和這個大同小異,想要詳細的了解可以參考:http://wiki.lbsyun.baidu.com/cms/androidsdk/doc/v3_7_0/
private PoiSearch mSearch ;// 搜索類 private int pageNum = 0; // 搜索的頁數- private void startPointSearch () { mSearch = PoiSearch.newInstance(); mSearch.setOnGetPoiSearchResultListener(this); // 檢索回調 PoiNearbySearchOption option = new PoiNearbySearchOption(); option.location( new LatLng( mLocation.getLatitude(), mLocation.getLongitude())); // 設置檢索的中心點 option.pageCapacity(50); // 設置檢索的返回的每頁的內容的條數 option.pageNum( pageNum); option.radius(30000); // 設置檢索的范圍,半徑。米為單位 option.sortType(PoiSortType. distance_from_near_to_far);// 設置排序由近到遠 option.keyword( "美食");// 搜索關鍵字 mSearch.searchNearby(option); // 開始檢索 pageNum++; } @Override public void onGetPoiDetailResult(PoiDetailResult arg0) { } // Poi檢索的回調,所有回調的結果都在這個PoiResult裡面,我們可以得到很多參數的信息 @Override public void onGetPoiResult(PoiResult arg0) { }
5:線路查詢(步行,駕車,公交) 根據4我們可以得到兩個POI興趣點,然後我們就可以查詢這兩個點的線路 線路查詢的關鍵類:RoutePlanSearch
private void startRouterResult( int type, String startAddr, String endAddr) { String cityName = new ShareDB(SearchInfoActivity.this ).getValue(DBConstants. CITY_NAME); PlanNode stNode = PlanNode.withCityNameAndPlaceName(cityName, startAddr); PlanNode enNode = PlanNode.withCityNameAndPlaceName(cityName, endAddr); if (type == 1) { routeSearch .transitSearch(new TransitRoutePlanOption().from(stNode).to(enNode).city(cityName)); } else if (type == 2) { routeSearch .drivingSearch(new DrivingRoutePlanOption().from(stNode).to(enNode)); } else if (type == 3) { routeSearch .walkingSearch(new WalkingRoutePlanOption().from(stNode).to(enNode)); } }
private void startRouterResult( final int type, LatLng beLat, LatLng endLat) { /*** * 此處應該判斷傳遞過來的經緯度是不是空的,因為有可能不是在listInfo集合裡面取出來的數據,如果為空,就要根據控件上的文字,進行坐標反查 * ,得到坐標,然後再調用這個方法 ||如果經緯度為空,則用地址信息來進行線路的查詢,不過此時查詢出來的結果可能為空 **/ if ( beLat != null && endLat != null) { String cityName = new ShareDB(SearchInfoActivity.this ).getValue(DBConstants. CITY_NAME); PlanNode stNode = PlanNode. withLocation(beLat ); PlanNode enNode = PlanNode. withLocation(endLat); if (type == 1) { routeSearch.transitSearch( new TransitRoutePlanOption().from(stNode).to(enNode).city(cityName)); } else if (type == 2) { routeSearch.drivingSearch( new DrivingRoutePlanOption().from(stNode).to(enNode)); } else if (type == 3) { routeSearch.walkingSearch( new WalkingRoutePlanOption().from(stNode).to(enNode)); } } }
/******************** 線路查詢返回的結果 ***********************/ // 因DrivingRouteResult、TransitRouteResult、WalkingRouteResult都是繼承SearchResult,沒有實現序列化,所以無法通過bundle來進行傳遞到下一個頁面。 // 1、可以通過自定義Model類來對數據進行封裝,實現序列化的接口來傳遞給下個界面 // 2、可以通過在Application類裡定義這三個類的對象,然後再此處賦值,在下一個界面的時候就直接得到(本次就是用的這個方法) @Override public void onGetDrivingRouteResult(DrivingRouteResult drivingRouteResult) { closeDialog(); if (drivingRouteResult. error.toString().equals( "NO_ERROR")) { BaseApplication. drivingRouteResult = drivingRouteResult; startIntent(2); } else { Toast. makeText(SearchInfoActivity. this, "未找到路線,請重新選擇起點或者終點" , Toast. LENGTH_SHORT).show(); } } @Override public void onGetTransitRouteResult(TransitRouteResult transitRouteResult) { closeDialog(); if (transitRouteResult. error.toString().equals( "NO_ERROR")) { BaseApplication. transitRouteResult = transitRouteResult; startIntent(1); } else { Toast. makeText(SearchInfoActivity. this, "未找到路線,請重新選擇起點或者終點" , Toast. LENGTH_SHORT).show(); } } @Override public void onGetWalkingRouteResult(WalkingRouteResult walkingRouteResult) { closeDialog(); if (walkingRouteResult. error.toString().equals( "NO_ERROR")) { BaseApplication. walkingRouteResult = walkingRouteResult; startIntent(3); } else { Toast. makeText(SearchInfoActivity. this, "未找到路線,請重新選擇起點或者終點" , Toast. LENGTH_SHORT).show(); } }線路規劃就到這裡結束了,接著就是線路的繪制了。 6:繪制線路(OpenGL和地圖SDK繪制) 步驟:1、得到經緯度集合,從5中線路查詢中得到的結果,比如WalkingRouteResult.getRouteLines() 會返回一個List
List繪制線路的兩種辦法: 1、OpenGL繪制,代碼如下:listLat = (List ) getIntent().getSerializableExtra( "latlng" );//得到經緯度集合 // 設置地圖類型 MAP_TYPE_NORMAL 普通圖; MAP_TYPE_SATELLITE 衛星圖 mBaiduMap.setMapType(BaiduMap. MAP_TYPE_NORMAL); // 開啟交通圖 mBaiduMap.setTrafficEnabled( true); MapStatusUpdate statusUpdate = MapStatusUpdateFactory.zoomTo(19); mBaiduMap.setMapStatus(statusUpdate); MyLatLng myLatLng = listLat.get(0); MapStatusUpdate u = MapStatusUpdateFactory. newLatLng( new LatLng(myLatLng.getLatitude(), myLatLng.getLongitude())); mBaiduMap.setMapStatus(u);
mBaiduMap .setOnMapDrawFrameCallback(callback ); /******************** 使用OpenGl繪制,是出現Bug,坐標的轉換和屏幕上的點的轉換,會隨著地圖大小的拉伸,OpenGl的線不拉伸的情況,建議不要使用此方法 *********************/ // 定義地圖繪制每一幀時 OpenGL 繪制的回調接口 OnMapDrawFrameCallback callback = new OnMapDrawFrameCallback() { public void onMapDrawFrame(GL10 gl, MapStatus drawingMapStatus) { if ( mBaiduMap.getProjection() != null) { // 計算折線的 opengl 坐標 calPolylinePoint(drawingMapStatus); // 繪制折線 drawPolyline(gl, Color. argb(255, 255, 0, 0), vertexBuffer, 10, 3, drawingMapStatus); } } }; // 計算折線 OpenGL 坐標 public void calPolylinePoint(MapStatus mspStatus) { PointF[] polyPoints = new PointF[ listLat.size()]; vertexs = new float[3 * listLat.size()]; int i = 0; for (MyLatLng xy : listLat) { // 將地理坐標轉換成 openGL 坐標 polyPoints[i] = mBaiduMap.getProjection().toOpenGLLocation( new LatLng(xy.getLatitude(), xy.getLongitude()), mspStatus); vertexs[i * 3] = polyPoints[i]. x; vertexs[i * 3 + 1] = polyPoints[i]. y; vertexs[i * 3 + 2] = 0.0f; i++; } vertexBuffer = makeFloatBuffer( vertexs); } // 創建OpenGL繪制時的頂點Buffer private FloatBuffer makeFloatBuffer( float[] fs) { ByteBuffer bb = ByteBuffer. allocateDirect(fs. length * 4); bb.order(ByteOrder. nativeOrder()); FloatBuffer fb = bb.asFloatBuffer(); fb.put(fs); fb.position(0); return fb; } // 繪制折線 private void drawPolyline(GL10 gl, int color, FloatBuffer lineVertexBuffer, float lineWidth, int pointSize, MapStatus drawingMapStatus) { gl.glEnable(GL10. GL_BLEND); gl.glEnableClientState(GL10. GL_VERTEX_ARRAY); gl.glBlendFunc(GL10. GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA ); float colorA = Color. alpha(color) / 255f; float colorR = Color. red(color) / 255f; float colorG = Color. green(color) / 255f; float colorB = Color. blue(color) / 255f; gl.glVertexPointer(3, GL10. GL_FLOAT, 0, lineVertexBuffer); gl.glColor4f(colorR, colorG, colorB, colorA); gl.glLineWidth(lineWidth); gl.glDrawArrays(GL10. GL_LINE_STRIP, 0, pointSize); gl.glDisable(GL10. GL_BLEND); gl.glDisableClientState(GL10. GL_VERTEX_ARRAY); }
/** * 地圖SDK提供多種結合圖形覆蓋物,利用這些圖形,可幫助您構建更加豐富多彩的地圖應用。目前提供的幾何圖形有:點(Dot)、折線( * Polyline)、弧線(Arc)、圓(Circle)、多邊形(Polygon)。 此處繪制折線 */ OverlayOptions polygonOption = new PolylineOptions().points(listLat ).color(Color.parseColor( "#FF0000")).width(7); // 在地圖上添加多邊形Option,用於顯示 mBaiduMap.addOverlay(polygonOption);這個百度地圖的集成的時間大概是2015年9月,所以SDK和最新的肯定多多少少有點差異的。
要做這種效果1- 整個自定義控件其實就是一個ArcMenu .(半圓形那一圈),左下角的圖標沒有加入進控件中。 2- 我基於他的類改了點。他是將左下角的關閉ic
對於Android的學習,需要掌握的東西有點多,需要我們認真,小心,不斷的進取。前天突然有個想法,覺得Mp3播放器是一個可以練習的項目,於是在網上搜了下,發現有人已經寫了
前言因為最近想和後台進行對接,昨天自己在Google上研究了半天關於Volley的內容,覺得很開心。因為原來覺得關於網絡這塊,一直是個很復雜的東西和流程,沒想到Googl
在Android 的程序中設置項可以說是一個必須要有的頁面。下面說一下如何寫一個基本的設置頁面。我們先來看一下常用安卓程序的設置頁面: