Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android教材 | 第三章 Android界面事件處理(一)—— 傑瑞教育原創教材試讀,android試讀

Android教材 | 第三章 Android界面事件處理(一)—— 傑瑞教育原創教材試讀,android試讀

編輯:關於android開發

Android教材 | 第三章 Android界面事件處理(一)—— 傑瑞教育原創教材試讀,android試讀


  前  言

JRedu

 Android應用開發中,除了界面編程外,另一個重要的內容就是組件的事件處理。在Android系統中,存在多種界面事件,比如觸摸事件、按鍵事件、點擊事件等。在用戶交互過程中,App必須為用戶提供響應邏輯,這種響應就是通過事件處理完成的。

 本章內容將詳細介紹Android事件的具體處理及常見事件。

 

3.1 Android 事件基礎知識

  Android中提供了兩種處理事件的方式:

基於監聽器的事件處理

基於回調的事件處理

  在事件處理過程中涉及到三個重要概念,具體如下:

事件:事件封裝了界面組件上發生的事件的具體信息。通過Event對象,可以獲取界面組件事件的相關信息。

事件源:事件產生的來源,通常是指界面上的各種組件,比如文本框、按鈕、窗口、菜單等。

事件監聽器:監聽事件源,並處理事件。

  三者之間的關系如圖3-1所示。

 (圖 3-1)

3.2 基於監聽器的Android事件處理

  Android中基於監聽的事件處理,最主要的做法是為界面組件綁定對應的事件監聽器。主要有四種實現方式:

內部類作為事件監聽器

匿名內部類作為事件監聽器

Activity作為監聽器

布局文件中直接綁定

 

3.2.1內部類作為事件監聽器

  內部類作為事件監聽器有兩個優點,一是在本類中可以復用該監聽器;二是作為內部類可以訪問外部類中的界面組件。下面通過實例講解具體用法。

  實例3-1:

程序清單3-1 布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="com.jredu.event.MainActivity">
    <TextView
        android:id="@+id/show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:layout_marginBottom="10dp"
        />
    <Button
        android:id="@+id/btnOK"
        android:layout_width="match_parent" //按鈕作為事件源
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:text="點擊"
        />
</LinearLayout>

 

  上面布局文件中含有1個按鈕,該按鈕作為事件源,當點擊該按鈕後將觸發點擊事件。為按鈕綁定事件監聽器的程序如下:

程序清單3-2 內部類作為監聽器
public class MainActivity extends AppCompatActivity {
    TextView show;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
        show = (TextView)findViewById(R.id.show);
        Button btn = (Button)findViewById(R.id.btnOK); //獲取布局文件中按鈕
        btn.setOnClickListener(new InnerListener()); //為按鈕綁定監聽器
    }
    private class  InnerListener implements View.OnClickListener{ //單擊事件的監聽器
        @Override
        public void onClick(View v) { //事件發生時,執行的方法
            show.setText("這是內部類作為事件監聽器!");
        }
    }
}

 

  程序中定義了一個內部類,該內部類實現了View.OnClickListener,將作為單擊事件的監聽器。實例運行效果如圖3-2。

 (圖 3-2)

  從該案例可以得出,基於監聽的事件處理編寫步驟如下:

 

3.2.2匿名內部類作為事件監聽器

使用匿名內部類作為事件監聽器是目前使用比較廣泛的一種事件監聽器形式。具體案例代碼如下:

程序清單3-3 匿名內部類作為事件監聽器
public class AnonymousListenerActivity extends Activity {
    TextView show;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
        show = (TextView)findViewById(R.id.show);
        Button btn = (Button)findViewById(R.id.btnOK);
        btn.setOnClickListener(new View.OnClickListener() { //匿名類作為監聽器
            @Override
            public void onClick(View v) {
                show.setText("這是匿名內部類作為事件監聽器!"); //事件處理方法
            }
        });
    }
}

 

  上面程序通過直接new一個匿名類作為監聽器,該形式應用廣泛,缺點是代碼可讀性差,語法不易掌握。

 

3.2.3Activity作為監聽器

  使用Activity作為監聽器,也是一種常見的事件監聽器形式。這種形式需要Activity實現對應的監聽器接口。具體案例代碼如下:

程序清單3-4 Activity作為事件監聽器
public class ActivityAsListener extends Activity implements View.OnClickListener{ //實現單擊監聽器接口
    TextView show;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_listener); 
        show = (TextView)findViewById(R.id.show); 
        findViewById(R.id.btnOK).setOnClickListener(this); //獲取按鈕,並綁定監聽器
        findViewById(R.id.btnCancel).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {  //實現接口中的單擊方法,根據組件ID的進行不同的處理。
switch (v.getId()){
            case R.id.btnOK:
                show.setText("確定:Activity作為事件監聽器!!");
                break;
            case R.id.btnCancel:
                show.setText("取消:Activity作為事件監聽器!!");
                break;
            default:
                break;
        }
    }
}

 

  上面程序使用了Activity作為監聽器,該形式的優點是在同一個事件處理方法中可以處理界面中多個相同的事件;缺點是使程序結構顯得比較混亂,可讀性較差。

 

3.2.4控件綁定

  最為簡潔的方式就是在布局文件中為標簽直接綁定事件處理方法。在Android大多數標簽都支持onClick屬性,通過該屬性可以為標簽直接綁定事件監聽器。

程序清單3-5 控件綁定布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context="com.jredu.event.MainActivity">

    <TextView
        android:id="@+id/show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:layout_marginBottom="10dp"
        />

    <Button
        android:id="@+id/btnOK"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:onClick="clickToShow" //通過onClick屬性綁定事件處理方法clickToShow
        android:text="確定"
        />

</LinearLayout>

 

程序清單3-6 控件綁定程序
public class TagBindActivity extends Activity {
    TextView show;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tag_listener);
        show = (TextView)findViewById(R.id.show);
    }
    public void clickToShow(View v){  //事件處理方法,參數v為事件源
        show.setText("通過標簽直接綁定事件監處理方法!!");
    }
}

 

3.2.5View中事件監聽器

  View中常見的事件監聽器如下表:

表3-1 監聽器
說明 View.onClickListener 點擊事件監聽器 View.onLongClickListener 長按事件監聽器 View.onKeyListener 鍵盤事件監聽器 View.onFocusChangeListener 焦點事件監聽器 View.onTouchListener 觸摸事件監聽器

  在基於回調函數的事件處理中,UI控件承擔了事件源和事件監聽器雙重職責。當觸發UI控件的事件時,該控件會調用相應的回調函數進行處理事件,程序員所要做事情就是在回調函數中編寫事件處理邏輯。下面以Android的觸摸事件為例,講解基於回調函數的事件處理方式。

  通過自定義組件並重寫onTouchEvent方法完成觸摸事件的處理。自定義組件的具體知識可參照第十四章內容。

程序清單3-7 自定義View並重寫onTouchEvent方法
public class TouchView extends View { //TouchView繼承自View
    private int x=0;
    private int y=0; 
    private Bitmap bitmap;
    private Paint mPaint;
    private boolean isPressed =false;
    public TouchView(Context context) {
        super(context);
        init(context);
    }

    public TouchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context){ 
        bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ship_center); //初始化圖片資源
        mPaint = new Paint(); //創建畫筆
        mPaint.setAntiAlias(true); //為圖片邊緣去鋸齒
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(bitmap,x,y,mPaint);
    }
    private int oX;
    private int oY;
    @Override
    public boolean onTouchEvent(MotionEvent event) { //事件參數,封裝事件相關信息
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN: //處理ACTION_DOWN觸摸事件,記錄觸摸點的坐標,並設置按下標識isPressed為true。
                oX = (int)event.getX();
                oY = (int)event.getY();
                isPressed = true;
                break;
            case MotionEvent.ACTION_UP:
                isPressed = false;
                break; 
            case MotionEvent.ACTION_MOVE: //處理ACTION_MOVE觸摸事件,計算移動的距離,並改變圖片的位置。
                if(isPressed) {
                    int mX = (int) event.getX() - oX;
                    int mY = (int) event.getY() - oY;
                    oX = (int) event.getX();
                    oY = (int) event.getY();
                    x += mX;
                    y += mY; 
                    invalidate(); //通知TouchView進行重繪
                }
                break;
        }
        return true;  //返回true,表明組件已經處理了該事件。
    }
}

 

在上面自定義的TouchView類中,我們重寫了onTouchEvent方法。該方法負責處理自定義組件TouchView的觸摸事件,案例效果如圖3-3.

 (圖3-3)

       如上面的案例程序,onTouchEvent方法處理了多種事件。當手指觸摸到屏幕、在屏幕上移動或者離開屏幕時,會分別觸發ACTION_DOWN、ACTION_MOVE和ACTION_UP事件。這些事件都由onTouchEvent進行處理。

       在View中除了onTouchEvent方法,還提供了用於處理其他事件的回調方法,具體參看表3-2。

表3-2 方法
說明 boolean onKeyDown(int keyCode,KeyEvent event) 處理手機按鍵按下事件 boolean onKeyUp(int keyCode,KeyEvent event) 處理手機按鍵抬起事件 boolean onKeyLongPress(int keyCode,KeyEvent event) 處理手機按鍵長按事件 boolean onTouchEvent(MotionEvent event) 處理手機的觸屏事件 boolean onTrackballEvent(MotionEvent event) 處理手機軌跡球事件

 

  通過表3-1,可以發現這些回調方法都有一個boolean類型的返回值,該返回值用於表明該方法有沒有處理完對應的事件。

 

  下面通過案例說明控件的事件傳遞過程。

程序清單3-8 自定義JreduButton並重寫onTouchEvent方法
public class JreduButton extends Button { //JreduButton繼承Button
    private Context mContext; 
    public JreduButton(Context context) {
        super(context);
        this.mContext = context;
    }

    public JreduButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) { //重寫onTouchEvent方法
        Toast t= Toast.makeText(this.mContext, "Button的onTouchEvent完成觸摸事件的處理!", Toast.LENGTH_LONG); //定義Toast對象,並設置Toast出現的位置
        t.setGravity(Gravity.CENTER,0,0); 
        t.show();
        return true;  //返回值為true,表明該方法處理了觸摸事件,該事件不再傳遞
    }
}

 

  重寫Activity中的onTouchEvent方法,同樣用於處理觸屏事件,Activity類的代碼如下:

程序清單3-9重寫Activity的onTouchEvent方法
public class EventActivity extends AppCompatActivity {
    TextView show;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event);
        show = (TextView)findViewById(R.id.show);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) { //重寫onTouchEvent的方法,在該方法中設置文本顯示內容
        show.setText("Activity的onTouchEvent處理了事件!");
        return true;
    }
}

 

運行上面的程序,效果如圖3-4。

(圖3-4)

將上面程序中自定義按鈕JreduButton中的onTouchEvent的返回值改為false。運行程序,效果如圖3-5。

(圖3-5)

基於監聽的事件處理和基於回調的事件處理二者並不是孤立,Android對同一個事件的處理往往會提供這兩種事件處理方式,比如針對觸屏事件、按鍵事件,具體參看下表:

表3-3 基於回調
基於監聽 onTouchEvent(MotionEvent event) View.onTouchListener onKeyDown(int keyCode,KeyEvent event) View.onKeyListener onKeyUp(int keyCode,KeyEvent event) View.onKeyListener

 

3.4 Android觸屏手勢操作

  通過上一節重寫View的onTouchEvent方法或是實現onTouchListener接口可以處理一些簡單的觸屏事件,比如按下、移動、抬起等。如果想要處理一些復雜的手勢,則很難處理。Android提供了GestureDetector類,通過該類可以識別手勢。

表3-4 手勢相關接口 類、接口
說明 GestureDetector 手勢識別類 OnGestureListener 手勢滑動監聽接口 OnDoubleTapListener 雙擊手勢監聽器接口 SimpleOnGestureListener OnGestureListener和OnDoubleTapListener的實現類

 

  下面我們通過一個案例來講解手勢識別類的具體用法,該案例通過手勢在屏幕上滑動可以完成圖片切換。

程序清單3-10 手勢布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:gravity="center"
    tools:context="com.jredu.gesture.MainActivity">

    <ImageView   //用於切換顯示圖片的ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/jredu01" />
</RelativeLayout>

 

程序清單3-11 手勢程序
public class MainActivity extends Activity {
    private GestureDetector detector;
    private ImageView imageView;
    private int index = 0;
    private int[] arr = {
            R.drawable.jredu01,R.drawable.jredu02,
            R.drawable.jredu03,R.drawable.jredu04};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
        detector = new GestureDetector(this,new SimpleGestureListener()); //創建手勢識別對象
        imageView = (ImageView)findViewById(R.id.img);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) { //將觸屏事件交由手勢識別對象處理
        return detector.onTouchEvent(event); 
    }

    private class SimpleGestureListener extends GestureDetector.SimpleOnGestureListener{
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if(e2.getX()-e1.getX()>30 && Math.abs(velocityX)>Math.abs(velocityY)){ //水平滑動距離大於30並且X軸速度大Y軸速度時進行圖片切換。
                index++;
                if(index>=arr.length){
                    index=0;
                }
                imageView.setImageResource(arr[index]);
            }
            return true;  //該事件已被處理。
        }
    }
}

 

  在上面程序中定義了一個手勢識別對象,並且該對象設置了一個手勢監聽器SimpleGestureListener。SimpleGesutreListener繼承了GestureDetector.SimpleOnGestureListener並重寫了onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)方法。該方法用於檢測滑屏手勢,方法中共有4個參數,分別為:

 

  該案例顯示效果如圖3-6.

 (圖3-6)

想要處理什麼樣的手勢,只需要實現監聽器對應的方法即可。除了上面的onFling方法,手勢監聽器中還包含下面這些方法。

表3-5 方法
所屬接口 說明 onDown(MotionEvent e) OnGestureListener 單擊,觸摸屏按下時觸發。 onSingleTapUp(MotionEvent e) OnGestureListener 抬起,手指離開屏幕時觸發。長按、滾動、滑動時不觸發。 onLangPress(MotionEvent) OnGestureListener 長按觸摸屏時觸發。 onShowPress(MotionEvent) OnGestureListener 短按觸摸屏時觸發。 onScroll(MotionEvent e1,MotionEvent e2,float distanceX,float distanceY) OnGestureListener 滾屏,觸摸屏按下後滾動觸發。 onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) OnGestureListener 滑屏,觸摸屏按下後快速移動並抬起,會先觸發滾動手勢,跟著觸發一個滑動手勢。 onDoubleTap(MotionEvent e) OnDoubleTapListener 雙擊,手指在觸屏上迅速點擊第二次是觸發。 onDoubleTapEvent(MotionEvent e) OnDoubleTapListener 雙擊的按下和抬起各觸發一次該事件。 onSingleTapConfirmed(MotionEvent e) OnDoubleTapListener 單擊確認。

 

編者按

  傑瑞教育原創系列教材將於年後與大家正式見面。為更好的借鑒讀者意見,我們將會陸續地在博客園推出一系列教材試讀。我們也熱忱的歡迎廣大博友與我們互動,提出寶貴意見。我們也將為積極互動的博友,免費提供我們的原創教材以及更多福利,也歡迎大家加入下方QQ群與我們交流,謝謝大家!

 

作者:傑瑞教育
出處:http://www.cnblogs.com/jerehedu/ 
版權聲明:本文版權歸煙台傑瑞教育科技有限公司和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
技術咨詢:JRedu技術交流  

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved