在上一篇文章中,我們講到了使用 ScrollView 和 HorizontalScrollView ,可以在同一時刻讓屏幕要麼在水平方向滾動,要麼在垂直方向滾動。但卻不能同時在水平和垂直兩個方向滾動。這篇文章的目的就是爲了解決同時在兩個方向滾動的問題。
1. 創建一個 Android Project ,將 desktop.png( 大小爲 1280 x 900) ,拷貝到 res/drawable-mdpi 文件夾下。
2. 修改 Activity 所對應的 Java 代碼,使之如下:
package com.pat.gui;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.GestureDetector.OnGestureListener;
import android.widget.Toast;
public class ScrollPicture extends Activity
implements
OnGestureListener
{
private int X = 0;
private int Y = 0;
private static int scrollX = 0;
private static int scrollY = 0;
PictureView main;
Bitmap bmp;
Bitmap adapt;
Resources res;
Paint paint;
GestureDetector gestureDetector;
DisplayMetrics dm;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
gestureDetector = new GestureDetector(this);
paint = new Paint();
// 獲取圖像
res = getResources();
bmp = BitmapFactory.decodeResource(res, R.drawable.desktop);
// 獲取圖像的寬度和高度
X = bmp.getWidth();
Y = bmp.getHeight();
// adapt 是 bmp 顯示在屏幕上的那部分圖像,見 PictureView 中的 handleScroll 方法
adapt = Bitmap.createBitmap(bmp);
main = new PictureView(this);
// 去掉標題欄
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 全屏顯示
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
//setContentView(R.layout.main);
setContentView(main, new ViewGroup.LayoutParams(X, Y));
// 以 landscape 方式顯示
this.setRequestedOrientation(Configuration.ORIENTATION_LANDSCAPE);
// 獲取屏幕尺寸
dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
}
// 屏幕翻轉時,要重新獲取 dm 。要使 onConfigurationChanged 可以被觸發,必須做到:
// 1. 在 AndroidManifest.xml 的 Activity 標籤中,增加屬性 android:configChanges="orientation"
// 2. 在 AndroidManifest.xml ,須增加權限:
// <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
// 當屏幕顯示有 landscape 變成 portrait ,或者有 portrait 變成 landscape 是,都會觸發 onConfigurationChanged
@Override
public void onConfigurationChanged(Configuration newConfig)
{
if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
{
// 獲取屏幕尺寸
dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
// 重新計算 adapt 。顯示 desktop.png 的左上角開始,佔整個屏幕尺寸大小的那部分
adapt = Bitmap.createBitmap(bmp, 0, 0, dm.widthPixels, dm.heightPixels);
// scrollX 和 scrollY 分別爲在水平或者垂直方向上,滾動的像素值
scrollX = 0;
scrollY = 0;
// 重畫
main.invalidate();
Toast.makeText(this, "(" + dm.widthPixels + ", " + dm.heightPixels + ")", Toast.LENGTH_SHORT).show();
}
if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
{
dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
adapt = Bitmap.createBitmap(bmp, 0, 0, dm.widthPixels, dm.heightPixels);
scrollX = 0;
scrollY = 0;
main.invalidate();
Toast.makeText(this, "(" + dm.widthPixels + ", " + dm.heightPixels + ")", Toast.LENGTH_SHORT).show();
}
// 下面這句必須存在,否則會出現異常
super.onConfigurationChanged(newConfig);
}
public boolean onTouchEvent(MotionEvent me)
{
return gestureDetector.onTouchEvent(me);
}
public boolean onDown(MotionEvent me)
{
return true;
}
public boolean onFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY)
{
return true;
}
public void onLongPress(MotionEvent me)
{
}
public boolean onScroll(MotionEvent me1, MotionEvent me2, float distanceX, float distanceY)
{
// distanceX 和 distanceY ,分別爲叫上次位置的滾動量,可以爲正,也可能爲負
main.handleScroll(distanceX, distanceY);
return true;
}
public void onShowPress(MotionEvent me)
{
}
public boolean onSingleTapUp(MotionEvent me)
{
return true;
}
class PictureView extends View
{
public PictureView(Context ctx)
{
super(ctx);
}
// 調用 invalidate 方法時,會觸發 onDraw 這個方法
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(adapt, 0, 0, paint);
}
public void handleScroll(float distanceX, float distanceY)
{
// 修正每次滾動後的 scrollX 和 scrollY 的值
scrollX += distanceX;
scrollY += distanceY;
if(scrollX < 0)
{
scrollX = 0;
}
if(scrollX > (X - dm.widthPixels))
{
scrollX = X - dm.widthPixels;
}
if(scrollY < 0)
{
scrollY = 0;
}
if(scrollY > (Y - dm.heightPixels))
{
scrollY = Y - dm.heightPixels;
}
// 重新獲取 adapt
adapt = Bitmap.createBitmap(bmp, scrollX, scrollY, dm.widthPixels, dm.heightPixels);
// 重畫
invalidate();
}
}
}
3. 修改 AndroidManifest.xml ,使之如下:
<? xml version = "1.0" encoding = "utf-8" ?>
< manifest xmlns:android = "http://schemas.android.com/apk/res/android"
package = "com.pat.gui"
android:versionCode = "1"
android:versionName = "1.0" >
< application android:icon = "@drawable/icon" android:label = "@string/app_name" >
< activity android:name = ".ScrollPicture"
android:label = "@string/app_name"
android:screenOrientation = "sensor"
android:configChanges = "orientation" >
< intent-filter >
< action android:name = "android.intent.action.MAIN" />
< category android:name = "android.intent.category.LAUNCHER" />
</ intent-filter >
</ activity >
</ application >
< uses-sdk android:minSdkVersion = "7" />
< uses-permission android:name = "android.permission.CHANGE_CONFIGURATION" />
</ manifest >
注意 AndroidManifest.xml 文件中, 3 行粗體字。其中的 android:screenOrientation="sensor" 表示,由手機的重力感應器來決定屏幕是以 landscape 或者 portrait 方式顯示。
運行結果:
結果表明可以同時在水平和垂直方向移動圖片。