مشخصات مقاله
-
3040
-
0.0
-
7112
-
0
-
1
مدیریت رخدادهای تک لمسی و چند لمسی در اندروید
مدیریت رخدادهای تک لمسی و چند لمسی در اندروید
این مبحث آموزشی شما را با رابط برنامه سازی کاربردی touch در اپلیکیشن های اندروید آشنا می سازد .
فهرست محتوا
1. قابلیت لمس در اندروید
- مبانی touch در اندروید
- رخداد single touch
- رخداد multi touch
- آموزش کلاس GestureDetector
2. تمرین : مثالی از Singletouch
- ترسیم با استفاده از قابلیت لمس
- Tracking (ردیابی)
3. تمرین ایجاد view با قابلیت multitouch
4. آموزش : ایجاد activity (ScaleGestureDetector)
قابلیت لمس در اندروید
مبانی touch در اندروید
کلاس استاندارد View در اندروید از رخدادهای مربوط به touch (لمس صفحه نمایش)پشتیبانی می کند . شما می توانید به رویدادهای touch در View ها و Activity های خود واکنش نشان دهید . اندروید قادر است از چندین pointer (اشاره گر) به طور همزمان پشتیبانی کند, به طور مثال انگشت هایی که با صفحه نمایش تماس و تعامل (interaction) دارند .
کلاس پایه (base class) ی که از قابلیت لمس پشتیبانی می کند MotionEvent می باشد, کلاس نام برده به واسطه ی تابع onTouchEvent() به Views ارسال می گردد . جهت واکنش نشان دادن به رخدادهای touch باید متد onTouchEvent() را بازنویسی (override) کرد .
کلاس MotionEvent حامل اطلاعات مربوط به رخدادهای touch می باشد برای مثال می توان از تعداد اشاره گرها, مختصات X/Y و همچنین اندازه و مقدار فشار هر اشاره گر سخن گفت .
چنانچه رویداد touch توسط view (نما) مدیریت شود, در آن صورت متد ذکر شده true باز می گرداند . سعی اندروید بیشتر بر یافتن آن view ی است که از همه کاملتر (deepest view) بوده و به منظور مدیریت رویدادهای touch, true برمی گرداند . اگر view مورد نظر جزئی از view دیگر بود (مقصود همان view پدر می باشد), در آن صورت نما یا view پدر با بازگرداندن true از متد onInterceptTouchEvent() می تواند صاحب این رویداد شود . این کار رخداد MotionEvent.ACTION_CANCEL را به view ی می فرستد که پیشتر (سابقاً) رویدادهای touch را دریافت کرده بود .
به منظور واکنش نشان دادن به رویدادهای touch در activity, یک OnTouchListener ویژه ی View های مربوطه ثبت کنید .
رخداد single touch
اگر تنها یک ورودی مورد استفاده قرار گرفت, در آن صورت می توانید توابع getY () و getX () را جهت دریافت موقعیت فعلی انگشت بکار ببرید . از طریق متد getAction() می توان عملیاتی که پیاده یا انجام شده را دریافت کرد . کلاس MotionEvent با ارائه ی ثابت (constant) های ذیل نوع عملیات (action) اجراشده را شناسایی یا تعیین می کند .
جدول 1. رخدادهای touch
رخداد multi touch
قابلیت لمس چند قسمت از صفحه نمایش از ویرایش 2.0 در اندروید کاربردی شده و در نسخه ی 2.2 این سیستم عامل بهبود یافت .
MotionEvent.ACTION_POINTER_DOWN و MotionEvent.ACTION_POINTER_UP به محض تماس انگشت دوم با صفحه نمایش فرستاده می شوند . ویژه ی تماس اولین انگشت که با صفحه نمایش برخورد می کند, رخدادهای MotionEvent.ACTION_DOWN و MotionEvent.ACTION_UP بکار برده می شوند .
تابع getPointerCount() در کلاس MotionEvent به برنامه نویس این امکان را می دهد که از تعداد انگشت های در حال تماس با صفحه نمایش آگاهی پیدا کند . تمامی رخدادها و موقعیت های اشاره گر ها در نمونه (instance) ی کلاس MotionEvent مشمول هستند که برنامه نویس در متد onTouch() آن ها را دریافت می کند .
به منظور ردیابی رخدادهای touch از چندین اشاره گر شما باید از توابع MotionEvent.getActionIndex() و MotionEvent.getActionMasked() جهت شناسایی شاخص اشاره گر و رویدادی که برای این اشاره گر رخ داده بهره بگیرید .
Pointer index (شاخص اشاره گر) فوق ممکن است در طول زمان تغییر کند, برای مثال زمانی که یک انگشت از سطح صفحه نمایش برداشته می شود. نوع پایای یک اشاره گر در واقع pointer id است که توسط متد getPointerId(pointerIndex) مشتق از شئ MotionEvent مشخص می شود . استفاده از آن در تکه کد زیر نمایش داده شده :
@Override
public boolean onTouchEvent(MotionEvent event) {
// get pointer index from the event object
int pointerIndex = event.getActionIndex();
// get pointer ID
int pointerId = event.getPointerId(pointerIndex);
// get masked (not specific to a pointer) action
int maskedAction = event.getActionMasked();
switch (maskedAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
// TODO use data
break;
}
case MotionEvent.ACTION_MOVE: { // a pointer was moved
// TODO use data
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL: {
// TODO use data
break;
}
}
invalidate();
return true;
}
نکته:
استفاده از امکان Multitouch در شبیه ساز ممکن نیست . برای این منظور باید از یک دستگاه اندروید به عنوان وسیله ی که ورودی دریافت می کند (input device) بهره جست .
آموزش کلاس GestureDetector
اندروید با ارائه ی کلاس GestureDetector امکان استفاده از MotionEvents و ایجاد رخدادهای مربوط به حرکات و gesture های پیشرفته تر و تخصیص گوش فراخوان ویژه آن ها را برای برنامه نویس فراهم می کند .
به طور مثال کلاس ScaleGestureDetector قابلیت مشخص کردن حرکت از پیش تعریف شده ی بزرگنمایی و کوچک نمایی شئ به وسیله ی دو انگشت را فراهم می کند .
تمرین : مثالی از Singletouch
ترسیم با استفاده از قابلیت لمس
Singletouch را با یک View سفارشی نمایش می دهیم.
برای این منظور پروژه ی com.vogella.android.touch.single را ایجاد کرده و activity آن را SingleTouchActivity را نام گذاری کنید .
حال کلاس SingleTouchEventView را مشابه زیر ایجاد کنید . کلاس مذکور View (نمایی) را پیاده سازی می کند که از قابلیت singletouch پشتیبانی می کند .
package de.vogella.android.touch.single;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class SingleTouchEventView extends View {
private Paint paint = new Paint();
private Path path = new Path();
public SingleTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(6f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
// Schedules a repaint.
invalidate();
return true;
}
}
اکنون View ایجاد شده را به activity خود اضافه کنید .
package de.vogella.android.touch.single;
import android.app.Activity;
import android.os.Bundle;
public class SingleTouchActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SingleTouchEventView(this, null));
}
}
در صورت اجرای برنامه متوجه خواهی شد که می توان با استفاده از یک انگشت روی صفحه نمایش دستگاه نقاشی کرد (یا در محیط شبیه ساز با استفاده از موس ترسیم را انجام داد) .
کدنویسی خود را گونه ای اصلاح کنید که بتوانید طرح کلی (layout) خود را بر اساس XML تعریف کنید . به منظور استفاده از view خود در تعریف طرح کلی مبتنی بر XML, باید حتماً از کل اسم کلاس (منظور اسم کلاس که دربردارنده ی اطلاعات پکیج باشد) استفاد کنید .
Tracking (ردیابی)
کدی به نمونه ترسیم خود اضافه کنید که موقعیت جاری انگشت را توسط یک دایره نشان دهد . به منظور ترسیم یک دایره شما می توانید تابع addCircle(x, y, 50, Path.Direction.CW) را روی یک Path فراخوانی کرده یا المان canvas را به طور مستقیم بکار ببرید .
مطمئن شوید که فقط موقعیت فعلی با استفاده از دایره برجسته (هایلات) می شود . دایره ی مورد نظر باید به محض اینکه انگشت پایین رفته و با صفحه تماس برقرار کرده نمایش داده شود و به مجرد بالا رفتن انگشت و قطع تماس آن با صفحه ناپدید شود .
تمرین ایجاد view با قابلیت multitouch
در این تمرین به ساخت view ی می پردازیم که قابلیت پشتیبانی از تماس چندین انگشت با نما یا صفحه نمایش را داشته باشد, همچنین امکان ردیابی آن ها را برای کاربر فراهم بیاورد. بر روی شبیه ساز باید singletouch را با استفاده از موس شبیه سازی کنید .
پروژه ی اندرویدی به نام com.vogella.android.multitouch ایجاد کرده, سپس به ساخت activity پروژه به نام MainActivity بپردازید .
کلاس MultitouchView را مشابه مثال زیر ایجاد کنید .
package com.vogella.android.multitouch;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
public class MultitouchView extends View {
private static final int SIZE = 60;
private SparseArray mActivePointers;
private Paint mPaint;
private int[] colors = { Color.BLUE, Color.GREEN, Color.MAGENTA,
Color.BLACK, Color.CYAN, Color.GRAY, Color.RED, Color.DKGRAY,
Color.LTGRAY, Color.YELLOW };
private Paint textPaint;
public MultitouchView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
private void initView() {
mActivePointers = new SparseArray();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// set painter color to a color you like
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(20);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// get pointer index from the event object
int pointerIndex = event.getActionIndex();
// get pointer ID
int pointerId = event.getPointerId(pointerIndex);
// get masked (not specific to a pointer) action
int maskedAction = event.getActionMasked();
switch (maskedAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
// We have a new pointer. Lets add it to the list of pointers
PointF f = new PointF();
f.x = event.getX(pointerIndex);
f.y = event.getY(pointerIndex);
mActivePointers.put(pointerId, f);
break;
}
case MotionEvent.ACTION_MOVE: { // a pointer was moved
for (int size = event.getPointerCount(), i = 0; i < size; i++) {
PointF point = mActivePointers.get(event.getPointerId(i));
if (point != null) {
point.x = event.getX(i);
point.y = event.getY(i);
}
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL: {
mActivePointers.remove(pointerId);
break;
}
}
invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw all pointers
for (int size = mActivePointers.size(), i = 0; i < size; i++) {
PointF point = mActivePointers.valueAt(i);
if (point != null)
mPaint.setColor(colors[i % 9]);
canvas.drawCircle(point.x, point.y, SIZE, mPaint);
}
canvas.drawText("Total pointers: " + mActivePointers.size(), 10, 40 , textPaint);
}
}
حال این view را به activity خود اضافه کنید .
RelativeLayout>
Activity تولید شده می تواند به همان شکل خود باقی بماند .
package com.vogella.android.multitouch;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
پس از اجرای برنامه خواهی دید که می توان با انگشت خود روی صفحه نمایش ترسیم انجام داد . البته لازم است بررسی کنید دستگاه مربوطه از چه تعداد اشاره گر بر روی صفحه نمایش به طور همزمان پشتیبانی می کند .
آموزش : ایجاد activity (ScaleGestureDetector)
پروژه ی جدیدی ایجاد کرده و نام آن را de.vogella.android.touch.scaledetector انتخاب کنید, سپس یک activity ویژه ی پروژه ی مزبور به نام ScaleDetectorTestActivity ایجاد کنید .
اکنون کلاسی درست مشابه نمونه ی زیر ایجاد کنید .
package de.vogella.android.touch.scaledetector;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
public class ImageViewWithZoom extends View {
private Drawable image;
private float scaleFactor = 1.0f;
private ScaleGestureDetector scaleGestureDetector;
public ImageViewWithZoom(Context context) {
super(context);
image = context.getResources().getDrawable(R.drawable.icon);
setFocusable(true);
image.setBounds(0, 0, image.getIntrinsicWidth(),
image.getIntrinsicHeight());
scaleGestureDetector = new ScaleGestureDetector(context,
new ScaleListener());
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Set the image bounderies
canvas.save();
canvas.scale(scaleFactor, scaleFactor);
image.draw(canvas);
canvas.restore();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
scaleGestureDetector.onTouchEvent(event);
invalidate();
return true;
}
private class ScaleListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
// don't let the object get too small or too large.
scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 5.0f));
invalidate();
return true;
}
}
}
این View را به activity نام برده اضافه کنید .
package de.vogella.android.touch.scaledetector;
import android.app.Activity;
import android.os.Bundle;
public class ScaleDetectorTestActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new ImageViewWithZoom(this));
}
}
پس از اجرای برنامه خواهی دید که می توان با استفاده از دو انگشت به طور همزمان (حرکت / multitouch) تصویر را بزرگ و کوچک کنید .