MotionEvent(一) 單點觸摸和事件傳遞

來源:互聯網
上載者:User

當觸摸android裝置的螢幕時,android系統將建立一個MotionEvent對象。

MotionEvent對象是描述了一組和使用者觸摸相關的事件序列,它包含了觸摸的位置,時間,動作等資訊。

發生觸摸時,這個MotionEvent對象會被傳遞到合適的方法中作為方法參數(通常是回調方法)。

getAction()方法描述了當前的動作:

ACTION_DOWN:手指按下     值:0ACTION_MOVE:手指移動   值:2ACTION_UP:手指彈起         值:1

像OnTouchListener的onTouch()回調方法就接受一個系統產生的MotionEvent,這類回調方法傳回值為boolean,如果返回true,那麼實現OnTouchListener的View會告訴android:我對此觸摸的事件序列以及以後會發生的觸摸事件序列都不感興趣,請你尋找下一個感興趣的View。android系統下次收到觸摸事件不會將MotionEvent的執行個體發送給這個View,而是尋找下一個接受MotionEvent的View。前後2個MotionEvent是同一個對象,而不是新產生的(下面的例子會驗證這個說法)

下面是Demo:

布局檔案: activity_main.xml

<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"    tools:context=".MainActivity" >        <RelativeLayout         android:id="@+id/truelayout"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:background="@android:color/black"        android:layout_weight="1"        android:tag="truelayout"        >        <com.example.mytouchdemo.TrueButton             android:id="@+id/truebutton"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textColor="@android:color/white"            android:tag="truebutton"            android:text="true"            />                <com.example.mytouchdemo.FalseButton            android:id="@+id/falsebutton"            android:layout_below="@+id/truebutton"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textColor="@android:color/white"            android:tag="falsebutton"            android:text="false"            />    </RelativeLayout>    <RelativeLayout         android:id="@+id/falselayout"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_weight="1"        android:tag="falselayout"        android:background="@android:color/darker_gray"        >        <com.example.mytouchdemo.TrueButton            android:id="@+id/falsebutton2"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:textColor="@android:color/white"            android:tag="falsebutton2"            android:text="false"            />    </RelativeLayout></LinearLayout>

TrueButton和FalseButton都是自訂控制項,繼承了BooleanButton,BooleanButton繼承了Button

BooleanButton的onTouchEvent回調在接收了MotionEvent對象,傳回值取決於是trueButton.還是falseButton..

public abstract class BooleanButton extends Button {    protected boolean myValue() {    return false;    }public BooleanButton(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean onTouchEvent(MotionEvent event) {Log.v(tag, "------"+ getTag() +"--------------");        Log.v(tag, "action:" + event.getAction());        Log.v(tag, "and I'm returning " + myValue());        Log.v(tag, "MotionEvent's hashcode="+event.hashCode()+"");        return(myValue());}private String tag = "test";}

public class TrueButton extends BooleanButton {    protected boolean myValue() {    return true;    }    public TrueButton(Context context, AttributeSet attrs) {super(context, attrs);}}

public class FalseButton extends BooleanButton {public FalseButton(Context context, AttributeSet attrs) {super(context, attrs);}}

MainActivity.java

public class MainActivity extends Activity implements OnTouchListener{@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//上半部分布局,ontouch方法返回trueRelativeLayout trueLayout = (RelativeLayout)findViewById(R.id.truelayout);//true按鈕,ontouch方法和自身的onTouchEvent方法返回trueButton trueButton = (Button)findViewById(R.id.truebutton);//false按鈕,ontouch方法和自身的onTouchEvent方法返回falseButton falseButton = (Button)findViewById(R.id.falsebutton);Button falseButton2 = (Button)findViewById(R.id.falsebutton2);//下半部分布局,ontouch方法返回falseRelativeLayout falseLayout = (RelativeLayout)findViewById(R.id.falselayout);//註冊ontouch事件trueLayout.setOnTouchListener(this);falseLayout.setOnTouchListener(this);trueButton.setOnTouchListener(this);falseButton.setOnTouchListener(this);falseButton2.setOnTouchListener(this);}@Overridepublic boolean onTouch(View v, MotionEvent event) {String tagStr = v.getTag().toString().substring(0, 4);//tag前4位元為true的控制項,onTouch返回true,否則返回falseif ("true".equals(tagStr)) {Log.v(tag, "------"+ v.getTag() +"--------------");        Log.v(tag, "action:" + event.getAction());        Log.v(tag, "and I'm returning " + tagStr);        Log.v(tag, "MotionEvent's hashcode="+event.hashCode()+"");return true;} else {return false;}}String tag = "test";}

現在啟動程式,點擊上半布局的TrueButton,檢查logcat輸出:

06-17 22:26:31.662: V/test(5766): ------truebutton--------------
06-17 22:26:31.662: V/test(5766): action:0
06-17 22:26:31.662: V/test(5766): and I'm returning true
06-17 22:26:31.662: V/test(5766): MotionEvent's hashcode=1097894832
06-17 22:26:31.682: V/test(5766): ------truebutton--------------
06-17 22:26:31.682: V/test(5766): action:2
06-17 22:26:31.682: V/test(5766): and I'm returning true
06-17 22:26:31.682: V/test(5766): MotionEvent's hashcode=1097894832
06-17 22:26:31.702: V/test(5766): ------truebutton--------------
06-17 22:26:31.702: V/test(5766): action:2
06-17 22:26:31.702: V/test(5766): and I'm returning true
06-17 22:26:31.702: V/test(5766): MotionEvent's hashcode=1097894832
06-17 22:26:31.712: V/test(5766): ------truebutton--------------
06-17 22:26:31.712: V/test(5766): action:1
06-17 22:26:31.712: V/test(5766): and I'm returning true
06-17 22:26:31.712: V/test(5766): MotionEvent's hashcode=1097894832

可以看到所有的事件都在truebutton中被接收了,包括按下action:0,移動action:2,彈起action:1。這是因為onTouch方法中返回了true。

現在點擊上半布局的FalseButton,檢查logcat輸出:

06-17 22:29:06.892: V/test(5766): ------falsebutton--------------
06-17 22:29:06.892: V/test(5766): action:0
06-17 22:29:06.892: V/test(5766): and I'm returning false
06-17 22:29:06.892: V/test(5766): MotionEvent's hashcode=1097894832
06-17 22:29:06.892: V/test(5766): ------truelayout--------------
06-17 22:29:06.892: V/test(5766): action:0
06-17 22:29:06.902: V/test(5766): and I'm returning true
06-17 22:29:06.902: V/test(5766): MotionEvent's hashcode=1097894832
06-17 22:29:06.912: V/test(5766): ------truelayout--------------
06-17 22:29:06.912: V/test(5766): action:2
06-17 22:29:06.912: V/test(5766): and I'm returning true
06-17 22:29:06.912: V/test(5766): MotionEvent's hashcode=1097894832
06-17 22:29:06.932: V/test(5766): ------truelayout--------------
06-17 22:29:06.932: V/test(5766): action:2
06-17 22:29:06.932: V/test(5766): and I'm returning true
06-17 22:29:06.932: V/test(5766): MotionEvent's hashcode=1097894832
06-17 22:29:06.952: V/test(5766): ------truelayout--------------
06-17 22:29:06.952: V/test(5766): action:2
06-17 22:29:06.952: V/test(5766): and I'm returning true
06-17 22:29:06.952: V/test(5766): MotionEvent's hashcode=1097894832
06-17 22:29:06.972: V/test(5766): ------truelayout--------------
06-17 22:29:06.972: V/test(5766): action:1
06-17 22:29:06.972: V/test(5766): and I'm returning true
06-17 22:29:06.972: V/test(5766): MotionEvent's hashcode=1097894832

看到falseButton和包含它的布局truelayout都接收了按下事件,但是之後的移動,彈起都只有truelayout接收。因為falseButton在onTouch中返回false,這表明它不再接收之後的觸摸時間,交由其他View處理,所以android系統找到了truelayout,因為truelayout的onTouch返回true,所以它處理所有的觸摸事件序列。並且注意到,2次接受的motionEvent的hashcode都是一樣的,說明他們是一個motionevent

下面點擊下半個布局的falsebutton,logcat輸出:

06-17 22:36:57.942: V/test(7164): ------falsebutton2--------------
06-17 22:36:57.942: V/test(7164): action:0
06-17 22:36:57.942: V/test(7164): and I'm returning false
06-17 22:36:57.942: V/test(7164): MotionEvent's hashcode=1098095696

可以看到非常悲劇,因為包含它的布局falselayout返回的也是false,現在沒有view可以接收motionevent對象,所以不能監聽到移動和彈起的事件

下面看一個特殊的情況:按住上半部分的trueButton並且移動手指一直到移出button外,移到relativelayout上。看log:

06-17 22:39:41.442: V/test(7164): ------truebutton--------------
06-17 22:39:41.442: V/test(7164): action:0
06-17 22:39:41.442: V/test(7164): and I'm returning true
06-17 22:39:41.442: V/test(7164): MotionEvent's hashcode=1098095696
06-17 22:39:41.462: V/test(7164): ------truebutton--------------
06-17 22:39:41.462: V/test(7164): action:2
06-17 22:39:41.462: V/test(7164): and I'm returning true
06-17 22:39:41.462: V/test(7164): MotionEvent's hashcode=1098095696

………………………………………………

你會發現就算出了button的範圍它依然監聽觸摸事件,這是因為它返回true,代表這一系列觸摸動作都由我來處理,這也是“觸摸序列”的含義

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.