Android開原始碼解讀の地圖照片應用Panoramio的實現詳解(六)

來源:互聯網
上載者:User

本文介紹檔案ViewImage.java和ViewMap.java。前者實現單張圖片資訊的瀏覽,後者實現自訂的地圖,用於顯示圖片拍攝地點和使用者當前所在地點。ViewImage實現的Activity介面如左,點擊手機的菜單鍵時,快顯功能表選項介面如右:

                                                                          

上面Activity用到的布局檔案view_image.xml如下:

<?xml version="1.0" encoding="utf-8"?></p><p><ScrollView xmlns:android="http://schemas.android.com/apk/res/android"<br /> android:layout_width="fill_parent"<br /> android:layout_height="fill_parent"<br /> android:fillViewport="true"></p><p><LinearLayout<br />android:id="@+id/content"<br /> android:orientation="vertical"<br /> android:layout_width="fill_parent"<br /> android:layout_height="fill_parent"<br /> android:gravity="center_horizontal"<br /> ></p><p> <FrameLayout<br /> android:layout_width="fill_parent"<br /> android:layout_height="0dip"<br /> android:layout_weight="1"<br /> android:padding="10dip"> </p><p> <LinearLayout<br /> android:orientation="vertical"<br /> android:layout_width="fill_parent"<br /> android:layout_height="wrap_content"<br /> android:layout_gravity="center"<br /> android:gravity="center_horizontal"<br /> ></p><p><ImageView<br />android:id="@+id/image"<br />android:layout_width="wrap_content"<br /> android:layout_height="wrap_content"<br /> android:background="@drawable/picture_frame"<br /> android:scaleType="fitCenter"<br /> android:adjustViewBounds="true"<br /> android:maxHeight="320dip"<br /> android:layout_alignParentTop="true"<br /> android:layout_centerHorizontal="true"<br /> /></p><p><TextView<br /> android:id="@+id/title"<br /> android:layout_width="wrap_content"<br /> android:layout_height="wrap_content"<br /> android:textSize="20dip"<br /> android:singleLine="true"<br /> android:ellipsize="end"<br /> android:textColor="?android:attr/textColorPrimary"<br /> android:paddingLeft="5dip"<br /> android:paddingRight="5dip"<br /> android:layout_alignLeft="@id/image"<br /> android:layout_alignRight="@id/image"<br /> android:layout_below="@id/image"<br /> /></p><p><TextView<br /> android:id="@+id/owner"<br /> android:layout_width="wrap_content"<br /> android:layout_height="wrap_content"<br /> android:textSize="16dip"<br /> android:singleLine="true"<br /> android:ellipsize="end"<br /> android:textColor="?android:attr/textColorPrimary"<br /> android:paddingLeft="5dip"<br /> android:paddingRight="5dip"<br />android:layout_alignLeft="@id/title"<br /> android:layout_alignRight="@id/title"<br />android:layout_below="@id/title"<br /> /><br /> </LinearLayout></p><p> </FrameLayout></p><p><TextView<br /> android:layout_width="fill_parent"<br /> android:layout_height="wrap_content"<br /> android:textSize="13dip"<br /> android:textColor="?android:attr/textColorSecondary"<br />android:text="@string/copyright"<br />android:gravity="center"<br />android:paddingLeft="10dip"<br />android:paddingRight="10dip"<br /> /></p><p></LinearLayout></p><p></ScrollView>

ViewImage根據從ImageList傳遞過來的URL等資訊,開啟後台線程從伺服器載入中等大小圖片資訊,用到的UI組件主要有菜單選項,提示對話方塊等。

菜單選項的實現需要重寫Activity的兩個函數:onCreateOptionsMenu和onOptionsItemSelected,程式架構如下:

import android.app.Activity;<br />import android.view.Menu;<br />import android.view.MenuItem;</p><p>public class MainActivity extends Activity {</p><p>@Override<br />public boolean onCreateOptionsMenu(Menu menu) {<br />// 在這個函數內建立菜單選項<br />return super.onCreateOptionsMenu(menu);<br />}</p><p>@Override<br />public boolean onOptionsItemSelected(MenuItem item) {<br />// 定義功能表項目被選中時的響應事件<br />return super.onOptionsItemSelected(item);<br />}</p><p>}

對話方塊的實現需要重寫Activity的onCreateDialog函數,並在函數中建立對話方塊。然後在需要顯示的地方調用Activity的showDialog函數,顯示onCreateDialog中建立的對話方塊。ViewImage的實現代碼如下:

package com.google.android.panoramio;</p><p>import com.google.android.maps.GeoPoint;</p><p>import android.app.Activity;<br />import android.app.AlertDialog;<br />import android.app.Dialog;<br />import android.content.ActivityNotFoundException;<br />import android.content.Intent;<br />import android.graphics.Bitmap;<br />import android.net.Uri;<br />import android.os.Bundle;<br />import android.os.Handler;<br />import android.util.Log;<br />import android.view.Menu;<br />import android.view.MenuItem;<br />import android.view.View;<br />import android.view.Window;<br />import android.widget.ImageView;<br />import android.widget.TextView;</p><p>/**<br /> * 顯示單張圖片的Activity<br /> */<br />public class ViewImage extends Activity {<br /> private static final String TAG = "Panoramio";</p><p> private static final int MENU_RADAR = Menu.FIRST + 1;</p><p> private static final int MENU_MAP = Menu.FIRST + 2;</p><p> private static final int MENU_AUTHOR = Menu.FIRST + 3;</p><p> private static final int MENU_VIEW = Menu.FIRST + 4;</p><p> private static final int DIALOG_NO_RADAR = 1;</p><p> PanoramioItem mItem;</p><p> private Handler mHandler;</p><p> private ImageView mImage;</p><p> private TextView mTitle;</p><p> private TextView mOwner;</p><p> private View mContent;</p><p> private int mMapZoom;</p><p> private int mMapLatitudeE6;</p><p> private int mMapLongitudeE6;</p><p> @Override<br /> protected void onCreate(Bundle savedInstanceState) {<br /> requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);<br /> super.onCreate(savedInstanceState);<br /> setContentView(R.layout.view_image);</p><p> // 從ImageList傳遞過來的搜尋地區資訊<br /> Intent i = getIntent();<br /> mItem = i.getParcelableExtra(ImageManager.PANORAMIO_ITEM_EXTRA);<br /> mMapZoom = i.getIntExtra(ImageManager.ZOOM_EXTRA, Integer.MIN_VALUE);<br /> mMapLatitudeE6 = i.getIntExtra(ImageManager.LATITUDE_E6_EXTRA, Integer.MIN_VALUE);<br /> mMapLongitudeE6 = i.getIntExtra(ImageManager.LONGITUDE_E6_EXTRA, Integer.MIN_VALUE);</p><p> mHandler = new Handler();</p><p> mContent = findViewById(R.id.content);<br /> mImage = (ImageView) findViewById(R.id.image);<br /> mTitle = (TextView) findViewById(R.id.title);<br /> mOwner = (TextView) findViewById(R.id.owner);</p><p> //初始化時將內容設定為不可見,等待後台線程載入資料完成後再顯示<br /> mContent.setVisibility(View.GONE);<br /> getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,<br /> Window.PROGRESS_VISIBILITY_ON);<br /> new LoadThread().start();<br /> }</p><p> @Override<br /> public boolean onCreateOptionsMenu(Menu menu) {<br /> super.onCreateOptionsMenu(menu);<br /> menu.add(0, MENU_RADAR, 0, R.string.menu_radar) //添加雷達功能表項目<br /> .setIcon(R.drawable.ic_menu_radar)<br /> .setAlphabeticShortcut('R');<br /> menu.add(0, MENU_MAP, 0, R.string.menu_map) //添加地圖功能表項目<br /> .setIcon(R.drawable.ic_menu_map)<br /> .setAlphabeticShortcut('M');<br /> menu.add(0, MENU_AUTHOR, 0, R.string.menu_author) //添加作者資訊功能表項目<br /> .setIcon(R.drawable.ic_menu_author)<br /> .setAlphabeticShortcut('A');<br /> menu.add(0, MENU_VIEW, 0, R.string.menu_view) //添加瀏覽器中瀏覽圖片功能表項目<br /> .setIcon(android.R.drawable.ic_menu_view)<br /> .setAlphabeticShortcut('V');<br /> return true;<br /> }</p><p> @Override<br /> public boolean onOptionsItemSelected(MenuItem item) {<br /> switch (item.getItemId()) {<br /> case MENU_RADAR: {<br /> // 啟動radar應用<br /> Intent i = new Intent("com.google.android.radar.SHOW_RADAR");<br /> GeoPoint location = mItem.getLocation();<br /> i.putExtra("latitude", (float)(location.getLatitudeE6() / 1000000f));<br /> i.putExtra("longitude", (float)(location.getLongitudeE6() / 1000000f));<br /> try {<br /> startActivity(i);<br /> } catch (ActivityNotFoundException ex) {<br /> showDialog(DIALOG_NO_RADAR); //radar應用不存在,彈出提示對話方塊<br /> }<br /> return true;<br /> }<br /> case MENU_MAP: {<br /> // 啟動自訂的地圖 ViewMap<br /> Intent i = new Intent(this, ViewMap.class);<br /> i.putExtra(ImageManager.PANORAMIO_ITEM_EXTRA, mItem);<br /> i.putExtra(ImageManager.ZOOM_EXTRA, mMapZoom);<br /> i.putExtra(ImageManager.LATITUDE_E6_EXTRA, mMapLatitudeE6);<br /> i.putExtra(ImageManager.LONGITUDE_E6_EXTRA, mMapLongitudeE6);</p><p> startActivity(i);</p><p> return true;<br /> }<br /> case MENU_AUTHOR: {<br /> // 在瀏覽器中顯示作者資訊<br /> Intent i = new Intent(Intent.ACTION_VIEW);<br /> i.setData(Uri.parse(mItem.getOwnerUrl()));<br /> startActivity(i);<br /> return true;<br /> }<br /> case MENU_VIEW: {<br /> // 在瀏覽器中顯示圖片資訊<br /> Intent i = new Intent(Intent.ACTION_VIEW);<br /> i.setData(Uri.parse(mItem.getPhotoUrl()));<br /> startActivity(i);<br /> return true;<br /> }<br /> }</p><p> return super.onOptionsItemSelected(item);<br /> }</p><p> @Override<br /> protected Dialog onCreateDialog(int id) {<br /> switch (id) {<br /> case DIALOG_NO_RADAR:<br /> //構造提示對話方塊<br /> AlertDialog.Builder builder = new AlertDialog.Builder(this);<br /> return builder.setTitle(R.string.no_radar_title)<br /> .setMessage(R.string.no_radar)<br /> .setIcon(android.R.drawable.ic_dialog_alert)<br /> .setPositiveButton(android.R.string.ok, null).create();<br /> }<br /> return null;<br /> }</p><p> /**<br /> * 用於載入medium大小位元影像的線程<br /> */<br /> private class LoadThread extends Thread {</p><p> public LoadThread() {<br /> }</p><p> @Override<br /> public void run() {<br /> try {<br /> String uri = mItem.getThumbUrl();<br /> uri = uri.replace("thumbnail", "medium"); //修改圖片URL<br /> final Bitmap b = BitmapUtils.loadBitmap(uri); //載入中等尺寸的位元影像</p><p> //通告UI線程更改介面<br /> mHandler.post(new Runnable() {<br /> public void run() {<br /> mImage.setImageBitmap(b);<br /> mTitle.setText(mItem.getTitle());<br /> mOwner.setText(mItem.getOwner());<br /> mContent.setVisibility(View.VISIBLE);<br /> getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,<br /> Window.PROGRESS_VISIBILITY_OFF);<br /> }<br /> });<br /> } catch (Exception e) {<br /> Log.e(TAG, e.toString());<br /> }<br /> }<br /> }</p><p>}

ViewMap繼承自MapActivity,用於在自訂地圖上顯示目前使用者位置和照片拍攝位置,實現的介面如:

                        

在Android中使用Google的地圖服務,需要實現MapView組件(或實現MapActivity),當程式中用到MapView時,需要在AndroidManifest.xml檔案的application標籤內添加類庫使用說明:

<uses-library android:name="com.google.android.maps" />

同時添加許可權許可說明如下:

<uses-permission android:name="android.permission.INTERNET"/>

具體代碼如下所示:

package com.google.android.panoramio;</p><p>import com.google.android.maps.GeoPoint;<br />import com.google.android.maps.MapActivity;<br />import com.google.android.maps.MapController;<br />import com.google.android.maps.MapView;<br />import com.google.android.maps.MyLocationOverlay;<br />import com.google.android.maps.Overlay;<br />import com.google.android.maps.Projection;</p><p>import android.content.Intent;<br />import android.graphics.Canvas;<br />import android.graphics.Point;<br />import android.graphics.drawable.Drawable;<br />import android.os.Bundle;<br />import android.view.Gravity;<br />import android.view.View;<br />import android.view.ViewGroup.LayoutParams;<br />import android.widget.FrameLayout;</p><p>import java.util.ArrayList;<br />import java.util.List;</p><p>/**<br /> * 自訂的地圖,顯示照片中所在地和使用者現在所在地點<br /> */<br />public class ViewMap extends MapActivity {<br /> private MapView mMapView;</p><p> private MyLocationOverlay mMyLocationOverlay;</p><p> ArrayList<PanoramioItem> mItems = null;</p><p> private PanoramioItem mItem;</p><p> private Drawable mMarker; //照片拍攝位置標識點</p><p> private int mMarkerXOffset; //標識點的X座標</p><p> private int mMarkerYOffset; //標識點的Y座標</p><p> @Override<br /> public void onCreate(Bundle savedInstanceState) {<br /> super.onCreate(savedInstanceState);</p><p> //代碼實現布局<br /> FrameLayout frame = new FrameLayout(this);<br /> mMapView = new MapView(this, "MapViewCompassDemo_DummyAPIKey");<br /> frame.addView(mMapView,<br /> new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));<br /> setContentView(frame);</p><p> mMyLocationOverlay = new MyLocationOverlay(this, mMapView);</p><p> //載入資源檔<br /> mMarker = getResources().getDrawable(R.drawable.map_pin);</p><p> // 給mMarker設定繪製在Overlay上的邊界<br /> final int intrinsicWidth = mMarker.getIntrinsicWidth();<br /> final int intrinsicHeight = mMarker.getIntrinsicHeight();<br /> mMarker.setBounds(0, 0, intrinsicWidth, intrinsicHeight);</p><p> mMarkerXOffset = -(intrinsicWidth / 2);<br /> mMarkerYOffset = -intrinsicHeight;</p><p> // 擷取從ViewImage傳遞過來的資料<br /> Intent i = getIntent();<br /> mItem = i.getParcelableExtra(ImageManager.PANORAMIO_ITEM_EXTRA);<br /> int mapZoom = i.getIntExtra(ImageManager.ZOOM_EXTRA, Integer.MIN_VALUE);<br /> int mapLatitudeE6 = i.getIntExtra(ImageManager.LATITUDE_E6_EXTRA, Integer.MIN_VALUE);<br /> int mapLongitudeE6 = i.getIntExtra(ImageManager.LONGITUDE_E6_EXTRA, Integer.MIN_VALUE);</p><p> //給MapView添加兩層Overlay<br /> final List<Overlay> overlays = mMapView.getOverlays();<br /> overlays.add(mMyLocationOverlay);<br /> overlays.add(new PanoramioOverlay());</p><p> //設定MapView的縮放層級和中心點<br /> final MapController controller = mMapView.getController();<br /> if (mapZoom != Integer.MIN_VALUE && mapLatitudeE6 != Integer.MIN_VALUE<br /> && mapLongitudeE6 != Integer.MIN_VALUE) {<br /> controller.setZoom(mapZoom);<br /> controller.setCenter(new GeoPoint(mapLatitudeE6, mapLongitudeE6));<br /> } else {<br /> //Locaiton擷取失敗,設定預設縮放層級為15,並給訊息佇列中添加一個Runnable對象<br /> //當Location修複時,將在新的線程中將地圖移動到指定中心點<br /> controller.setZoom(15);<br /> mMyLocationOverlay.runOnFirstFix(new Runnable() {<br /> public void run() {<br /> controller.animateTo(mMyLocationOverlay.getMyLocation());<br /> }<br /> });<br /> }</p><p> mMapView.setClickable(true);<br /> mMapView.setEnabled(true);<br /> mMapView.setSatellite(true);<br /> addZoomControls(frame); //給地圖添加縮放控制組件<br /> }</p><p> @Override<br /> protected void onResume() {<br /> super.onResume();<br /> //嘗試使能Location服務,該函數註冊為LocationManager.GPS_PROVIDER和<br /> //LocationManager.NETWORK_PROVIDER的觀察者<br /> mMyLocationOverlay.enableMyLocation();<br /> }</p><p> @Override<br /> protected void onStop() {<br /> //停止Location更新<br /> mMyLocationOverlay.disableMyLocation();<br /> super.onStop();<br /> }</p><p> /**<br /> * 擷取縮放控制組件,並添加到MapView視圖的下方<br /> */<br /> @SuppressWarnings("deprecation")<br />private void addZoomControls(FrameLayout frame) {<br /> View zoomControls = mMapView.getZoomControls();</p><p> FrameLayout.LayoutParams p =<br /> new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,<br /> LayoutParams.WRAP_CONTENT, Gravity.BOTTOM + Gravity.CENTER_HORIZONTAL);<br /> //將地圖縮放組件放到地圖MapView的下方<br /> frame.addView(zoomControls, p);<br /> }</p><p> @Override<br /> protected boolean isRouteDisplayed() {<br /> return false; //不支援路線資訊顯示<br /> }</p><p> /**<br /> * 顯示照片拍攝地點圖釘資源的Overlay<br /> */<br /> public class PanoramioOverlay extends Overlay {<br /> @Override<br /> public void draw(Canvas canvas, MapView mapView, boolean shadow) {<br /> if (!shadow) {<br /> Point point = new Point();<br /> //擷取投影類,在螢幕像素點和經緯度座標點之間轉換<br /> Projection p = mapView.getProjection();<br /> //將經緯度點資訊GeoPoint對象轉換成MapView視圖上的座標點Point對象<br /> p.toPixels(mItem.getLocation(), point);<br /> super.draw(canvas, mapView, shadow);<br /> //在指定的x和y座標點上繪製drawable對象mMarker<br /> drawAt(canvas, mMarker, point.x + mMarkerXOffset, point.y + mMarkerYOffset, shadow);<br /> }<br /> }<br /> }</p><p>}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.