您的位置:首页 > 移动开发 > Android开发

Android开源代码解读の地图照片应用Panoramio的实现详解(六)

2012-02-26 10:59 405 查看
本文介绍文件ViewImage.java和ViewMap.java。前者实现单张图片信息的浏览,后者实现自定义的地图,用于显示图片拍摄地点和用户当前所在地点。ViewImage实现的Activity界面如左下图,点击手机的菜单键时,弹出菜单选项界面如右下图:





上面Activity用到的布局文件view_image.xml如下:

<?xml version="1.0" encoding="utf-8"?>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true">

<LinearLayout
android:id="@+id/content"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
>

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:padding="10dip">

<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal"
>

<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/picture_frame"
android:scaleType="fitCenter"
android:adjustViewBounds="true"
android:maxHeight="320dip"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
/>

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dip"
android:singleLine="true"
android:ellipsize="end"
android:textColor="?android:attr/textColorPrimary"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:layout_alignLeft="@id/image"
android:layout_alignRight="@id/image"
android:layout_below="@id/image"
/>

<TextView
android:id="@+id/owner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dip"
android:singleLine="true"
android:ellipsize="end"
android:textColor="?android:attr/textColorPrimary"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:layout_alignLeft="@id/title"
android:layout_alignRight="@id/title"
android:layout_below="@id/title"
/>
</LinearLayout>

</FrameLayout>

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="13dip"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/copyright"
android:gravity="center"
android:paddingLeft="10dip"
android:paddingRight="10dip"
/>

</LinearLayout>

</ScrollView>

ViewImage根据从ImageList传递过来的URL等信息,开启后台线程从服务器加载中等大小图片信息,用到的UI组件主要有菜单选项,提示对话框等。

菜单选项的实现需要重写Activity的两个函数:onCreateOptionsMenu和onOptionsItemSelected,程序框架如下:

import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// 在这个函数内创建菜单选项
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 定义菜单项被选中时的响应事件
return super.onOptionsItemSelected(item);
}

}

对话框的实现需要重写Activity的onCreateDialog函数,并在函数中创建对话框。然后在需要显示的地方调用Activity的showDialog函数,显示onCreateDialog中创建的对话框。ViewImage的实现代码如下:

package com.google.android.panoramio;

import com.google.android.maps.GeoPoint;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.ImageView;
import android.widget.TextView;

/**
* 显示单张图片的Activity
*/
public class ViewImage extends Activity {
private static final String TAG = "Panoramio";

private static final int MENU_RADAR = Menu.FIRST + 1;

private static final int MENU_MAP = Menu.FIRST + 2;

private static final int MENU_AUTHOR = Menu.FIRST + 3;

private static final int MENU_VIEW = Menu.FIRST + 4;

private static final int DIALOG_NO_RADAR = 1;

PanoramioItem mItem;

private Handler mHandler;

private ImageView mImage;

private TextView mTitle;

private TextView mOwner;

private View mContent;

private int mMapZoom;

private int mMapLatitudeE6;

private int mMapLongitudeE6;

@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
super.onCreate(savedInstanceState);
setContentView(R.layout.view_image);

// 从ImageList传递过来的搜索区域信息
Intent i = getIntent();
mItem = i.getParcelableExtra(ImageManager.PANORAMIO_ITEM_EXTRA);
mMapZoom = i.getIntExtra(ImageManager.ZOOM_EXTRA, Integer.MIN_VALUE);
mMapLatitudeE6 = i.getIntExtra(ImageManager.LATITUDE_E6_EXTRA, Integer.MIN_VALUE);
mMapLongitudeE6 = i.getIntExtra(ImageManager.LONGITUDE_E6_EXTRA, Integer.MIN_VALUE);

mHandler = new Handler();

mContent = findViewById(R.id.content);
mImage = (ImageView) findViewById(R.id.image);
mTitle = (TextView) findViewById(R.id.title);
mOwner = (TextView) findViewById(R.id.owner);

//初始化时将内容设置为不可见,等待后台线程加载数据完成后再显示
mContent.setVisibility(View.GONE);
getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
Window.PROGRESS_VISIBILITY_ON);
new LoadThread().start();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_RADAR, 0, R.string.menu_radar) //添加雷达菜单项
.setIcon(R.drawable.ic_menu_radar)
.setAlphabeticShortcut('R');
menu.add(0, MENU_MAP, 0, R.string.menu_map) //添加地图菜单项
.setIcon(R.drawable.ic_menu_map)
.setAlphabeticShortcut('M');
menu.add(0, MENU_AUTHOR, 0, R.string.menu_author) //添加作者信息菜单项
.setIcon(R.drawable.ic_menu_author)
.setAlphabeticShortcut('A');
menu.add(0, MENU_VIEW, 0, R.string.menu_view) //添加浏览器中浏览图片菜单项
.setIcon(android.R.drawable.ic_menu_view)
.setAlphabeticShortcut('V');
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_RADAR: {
// 启动radar应用
Intent i = new Intent("com.google.android.radar.SHOW_RADAR");
GeoPoint location = mItem.getLocation();
i.putExtra("latitude", (float)(location.getLatitudeE6() / 1000000f));
i.putExtra("longitude", (float)(location.getLongitudeE6() / 1000000f));
try {
startActivity(i);
} catch (ActivityNotFoundException ex) {
showDialog(DIALOG_NO_RADAR); //radar应用不存在,弹出提示对话框
}
return true;
}
case MENU_MAP: {
// 启动自定义的地图 ViewMap
Intent i = new Intent(this, ViewMap.class);
i.putExtra(ImageManager.PANORAMIO_ITEM_EXTRA, mItem);
i.putExtra(ImageManager.ZOOM_EXTRA, mMapZoom);
i.putExtra(ImageManager.LATITUDE_E6_EXTRA, mMapLatitudeE6);
i.putExtra(ImageManager.LONGITUDE_E6_EXTRA, mMapLongitudeE6);

startActivity(i);

return true;
}
case MENU_AUTHOR: {
// 在浏览器中显示作者信息
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(mItem.getOwnerUrl()));
startActivity(i);
return true;
}
case MENU_VIEW: {
// 在浏览器中显示图片信息
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(mItem.getPhotoUrl()));
startActivity(i);
return true;
}
}

return super.onOptionsItemSelected(item);
}

@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_NO_RADAR:
//构造提示对话框
AlertDialog.Builder builder = new AlertDialog.Builder(this);
return builder.setTitle(R.string.no_radar_title)
.setMessage(R.string.no_radar)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.ok, null).create();
}
return null;
}

/**
* 用于加载medium大小位图的线程
*/
private class LoadThread extends Thread {

public LoadThread() {
}

@Override
public void run() {
try {
String uri = mItem.getThumbUrl();
uri = uri.replace("thumbnail", "medium"); //修改图片URL
final Bitmap b = BitmapUtils.loadBitmap(uri); //加载中等尺寸的位图

//通告UI线程更改界面
mHandler.post(new Runnable() {
public void run() {
mImage.setImageBitmap(b);
mTitle.setText(mItem.getTitle());
mOwner.setText(mItem.getOwner());
mContent.setVisibility(View.VISIBLE);
getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
Window.PROGRESS_VISIBILITY_OFF);
}
});
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}

}

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;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;

import java.util.ArrayList;
import java.util.List;

/**
* 自定义的地图,显示照片中所在地和用户现在所在地点
*/
public class ViewMap extends MapActivity {
private MapView mMapView;

private MyLocationOverlay mMyLocationOverlay;

ArrayList<PanoramioItem> mItems = null;

private PanoramioItem mItem;

private Drawable mMarker; //照片拍摄位置标识点

private int mMarkerXOffset; //标识点的X坐标

private int mMarkerYOffset; //标识点的Y坐标

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//代码实现布局
FrameLayout frame = new FrameLayout(this);
mMapView = new MapView(this, "MapViewCompassDemo_DummyAPIKey");
frame.addView(mMapView,
new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
setContentView(frame);

mMyLocationOverlay = new MyLocationOverlay(this, mMapView);

//加载资源文件
mMarker = getResources().getDrawable(R.drawable.map_pin);

// 给mMarker设置绘制在Overlay上的边界
final int intrinsicWidth = mMarker.getIntrinsicWidth();
final int intrinsicHeight = mMarker.getIntrinsicHeight();
mMarker.setBounds(0, 0, intrinsicWidth, intrinsicHeight);

mMarkerXOffset = -(intrinsicWidth / 2);
mMarkerYOffset = -intrinsicHeight;

// 获取从ViewImage传递过来的数据
Intent i = getIntent();
mItem = i.getParcelableExtra(ImageManager.PANORAMIO_ITEM_EXTRA);
int mapZoom = i.getIntExtra(ImageManager.ZOOM_EXTRA, Integer.MIN_VALUE);
int mapLatitudeE6 = i.getIntExtra(ImageManager.LATITUDE_E6_EXTRA, Integer.MIN_VALUE);
int mapLongitudeE6 = i.getIntExtra(ImageManager.LONGITUDE_E6_EXTRA, Integer.MIN_VALUE);

//给MapView添加两层Overlay
final List<Overlay> overlays = mMapView.getOverlays();
overlays.add(mMyLocationOverlay);
overlays.add(new PanoramioOverlay());

//设置MapView的缩放级别和中心点
final MapController controller = mMapView.getController();
if (mapZoom != Integer.MIN_VALUE && mapLatitudeE6 != Integer.MIN_VALUE
&& mapLongitudeE6 != Integer.MIN_VALUE) {
controller.setZoom(mapZoom);
controller.setCenter(new GeoPoint(mapLatitudeE6, mapLongitudeE6));
} else {
//Locaiton获取失败,设置默认缩放级别为15,并给消息队列中添加一个Runnable对象
//当Location修复时,将在新的线程中将地图移动到指定中心点
controller.setZoom(15);
mMyLocationOverlay.runOnFirstFix(new Runnable() {
public void run() {
controller.animateTo(mMyLocationOverlay.getMyLocation());
}
});
}

mMapView.setClickable(true);
mMapView.setEnabled(true);
mMapView.setSatellite(true);
addZoomControls(frame); //给地图添加缩放控制组件
}

@Override
protected void onResume() {
super.onResume();
//尝试使能Location服务,该函数注册为LocationManager.GPS_PROVIDER和
//LocationManager.NETWORK_PROVIDER的观察者
mMyLocationOverlay.enableMyLocation();
}

@Override
protected void onStop() {
//停止Location更新
mMyLocationOverlay.disableMyLocation();
super.onStop();
}

/**
* 获取缩放控制组件,并添加到MapView视图的下方
*/
@SuppressWarnings("deprecation")
private void addZoomControls(FrameLayout frame) {
View zoomControls = mMapView.getZoomControls();

FrameLayout.LayoutParams p =
new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT, Gravity.BOTTOM + Gravity.CENTER_HORIZONTAL);
//将地图缩放组件放到地图MapView的下方
frame.addView(zoomControls, p);
}

@Override
protected boolean isRouteDisplayed() {
return false; //不支持路线信息显示
}

/**
* 显示照片拍摄地点图钉资源的Overlay
*/
public class PanoramioOverlay extends Overlay {
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if (!shadow) {
Point point = new Point();
//获取投影类,在屏幕像素点和经纬度坐标点之间转换
Projection p = mapView.getProjection();
//将经纬度点信息GeoPoint对象转换成MapView视图上的坐标点Point对象
p.toPixels(mItem.getLocation(), point);
super.draw(canvas, mapView, shadow);
//在指定的x和y坐标点上绘制drawable对象mMarker
drawAt(canvas, mMarker, point.x + mMarkerXOffset, point.y + mMarkerYOffset, shadow);
}
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐