Android之按鈕點擊事件

在佈局文件中添加按鈕點擊事件

1、在xml文件中 爲 Button 添加android:onclick屬性

<Button
    android:id="@+id/btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="btn"
    android:textAllCaps="false"
    android:onClick="showMsg"/>

android:onclick屬性的值"showMsg"即爲用戶點擊屏幕按鈕時觸發方法的名字。
PS:Android系統會自動對Button中的所有英文字母轉換成大寫,android:textAllCaps屬性的值設置爲“false”可以禁用此設置。

2、在對應的.java文件中添加名爲showMsg的方法

此方法需滿足以下條件:

  • 與xml佈局文件中名稱一致
  • 是public函數
  • 無返回值(void 類型)
  • 參數唯一(爲View類型,代表被點擊的視圖)
/** Called when the user clicks the Button named btn */
public void showMsg(View view){
    Toast.makeText(MainActivity.this, "btn is clicked!", Toast.LENGTH_SHORT).show();
}

在java文件中添加按鈕點擊事件

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
         final Button btn = (Button) findViewById(R.id.btn);
         btn.setOnClickListener(new View.OnClickListener() {
            @Override
             public void onClick(View v) {
                 // Perform action on click
                 Toast.makeText(MainActivity.this, "btn is clicked!", Toast.LENGTH_SHORT).show();
             }
         });
    }
}

setOnClickListener()方法爲Button的點擊事件註冊了一個監聽器,每當點擊按鈕時,就會執行監聽器中的onClick()方法。

爲多個按鈕添加點擊事件

處理多個按鈕的點擊事件時,可以使用上面的方式爲每個按鈕分別綁定事件監聽器,也可以使用下面的方式定義一個實現監聽器的類,當然,下面的方式結構更加清晰。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button btn = (Button) findViewById(R.id.btn);
        final Button btn2 = (Button) findViewById(R.id.btn2);
        final Button btn3 = (Button) findViewById(R.id.btn3);

        OnClick onClick = new OnClick();
        btn.setOnClickListener(onClick);
        btn2.setOnClickListener(onClick);
        btn3.setOnClickListener(onClick);
    }

    private class OnClick implements View.OnClickListener{

        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.btn:
                    Log.d("btn listener:", "btn is clicked!");
                    break;
                case R.id.btn2:
                    Log.d("btn listener:", "btn2 is clicked!");
                    break;
                case R.id.btn3:
                    Log.d("btn listener:", "btn3 is clicked!");
                    break;
                default:
                    break;
            }
        }
    }
}

按鈕按下、釋放事件

一個按鈕點擊的完整過程是:pressed + released = clicked,所以當按下按鈕並滑動到按鈕之外的區域釋放時,點擊事件並不會觸發。如果需要分別處理按鈕的按下和釋放事件則可以使用下面的方式。

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        final Button btn = (Button) findViewById(R.id.btn);
        btn.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(v.getId() == R.id.btn){
                    if(event.getAction() == MotionEvent.ACTION_DOWN){
                        Log.e("btn listener:", "btn is pressed!");
                    }
                    else if(event.getAction() == MotionEvent.ACTION_UP){
                        Log.e("btn listener:", "btn is released!");
                    }
                }
                return false;
            }
        });
    } 
}

按鈕長按事件

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("btn listener:", "btn is clicked!");
            }
        });
        btn.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                Log.d("btn listener:", "btn is longClicked!");
                return false;
            }
        });
    }
}

PS:上面的代碼運行後會先打印btn listener:: btn is longClicked!,然後打印btn listener:: btn is clicked!,因爲按鈕長按時仍然會觸發點擊事件。如果只需要處理長按事件的話則不需考慮這一點,如果要在同一個按鈕單擊或長按時處理不同的內容,則需在長按時過濾掉單擊事件。

按鈕長按時過濾掉單擊事件

btn.setOnLongClickListener(new View.OnLongClickListener(){
    @Override
    public boolean onLongClick(View v){
        Log.d("btn listener:","btn is longClicked!");
        return true;
    }
});

將此處長按事件的返回值改爲true即可過濾掉單擊事件。
這裏涉及到事件傳播的問題,當處理事件的返回值爲false時表示該事件未完全處理完畢,事件會繼續向下傳播。

按鈕雙擊事件

public class MainActivity extends AppCompatActivity {

    private static final long CLICK_INTERVAL_TIME = 300;
    private static long lastClickTime = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //獲取系統當前毫秒數,從開機到現在的毫秒數(手機睡眠時間不包括在內)
                long currentTimeMillis = SystemClock.uptimeMillis();
                //兩次點擊間隔時間小於300ms代表雙擊
                if (currentTimeMillis - lastClickTime < CLICK_INTERVAL_TIME) {
                    Log.d("btn listener:", "btn is doubleClicked!");
                    return;
                }
                lastClickTime = currentTimeMillis;
                Log.d("btn listener:", "btn is clicked!");
            }
        });
    }
}

PS:使用System.currentTimeMillis()獲取系統當前毫秒數,是從1970年1月1日UTC到現在的毫秒數,如果系統時間被修改,此毫秒數會不正確。
PS:上面的代碼運行後會先打印btn listener:: btn is clicked!,然後打印btn listener:: btn is doubleClicked!,因爲按鈕雙擊時仍然會先觸發單擊事件。如果只需要處理雙擊事件的話則不需考慮這一點,如果要在同一個按鈕單擊或雙擊時處理不同的內容,則需在雙擊時過濾掉單擊事件。

按鈕雙擊時過濾掉單擊事件

雙擊時過濾單擊事件的思路可參考以前在Qt中的應用(QML之MouseArea雙擊時過濾掉單擊事件):在按鈕點擊時開啓定時器,判斷300ms內有沒有第二次點擊,有的話表示雙擊,沒有的話表示單擊。這裏使用HandlerpostDelayed()方法來處理延時。

public class MainActivity extends AppCompatActivity {

    private int clickNum = 0;
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button btn = (Button) findViewById(R.id.btn);
        final Button btn2 = (Button) findViewById(R.id.btn2);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clickNum++;
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (clickNum == 1) {
                            Log.d("btn listener:", "btn is clicked!");
                        }else if(clickNum==2){
                            Log.d("btn listener:", "btn is doubleClicked!");
                        }
                        //防止handler引起的內存泄漏
                        handler.removeCallbacksAndMessages(null);
                        clickNum = 0;
                    }
                },300);
            }
        });
    }
}

PSHandlerremoveCallbacksAndMessages(null)方法會移除所有的callbacks和messages,可有效避免Handler引起的內存泄漏。removeCallbacks(Runnable r) 方法可以移除即將發佈到消息隊列中的Runnable對象,終止延時。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章