Saya mengalami masalah dengan Tombol saya tetap dalam keadaan yang disorot, setelah melakukan hal berikut:
public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
v.performClick();
Log.d("Test", "Performing click");
return true;
}
}
return false;
}
});
}
}
Mengenai kode di atas, ketika menggunakannya, saya mengharapkan klik tombol untuk ditangani oleh sentuhan, dan dengan mengembalikan "benar" penanganannya harus berhenti di touchListener.
Tapi ini bukan masalahnya. Tombol tetap dalam kondisi yang disorot, meskipun klik dipanggil.
Apa yang saya dapatkan adalah:
Test - calling onClick
Test - Performing click
di sisi lain, jika saya menggunakan kode berikut, tombol diklik, cetakan yang sama, tetapi tombol tidak berakhir terjebak dalam keadaan yang disorot:
public class MainActivity extends AppCompatActivity {
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppCompatButton button = (AppCompatButton) findViewById(R.id.mybutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Test", "calling onClick");
}
});
button.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
v.getBackground().setColorFilter(0xe0f47521,PorterDuff.Mode.SRC_ATOP);
v.invalidate();
break;
}
case MotionEvent.ACTION_UP: {
v.getBackground().clearColorFilter();
v.invalidate();
// v.performClick();
Log.d("Test", "Performing click");
return false;
}
}
return false;
}
});
}
}
Saya agak bingung apa rantai responden untuk acara sentuhan. Dugaan saya adalah:
1) TouchListener
2) DaftarKlik
3) ParentViews
Bisakah seseorang mengonfirmasi hal ini juga?
Jawaban:
Kustomisasi semacam itu tidak memerlukan modifikasi terprogram. Anda dapat melakukannya hanya dalam
xml
file. Pertama-tama, hapussetOnTouchListener
metode yang Anda berikanonCreate
sepenuhnya. Selanjutnya, tentukan warna pemilih dalamres/color
direktori seperti berikut. (jika direktori tidak ada, buat itu)res / color / button_tint_color.xml
Sekarang, atur ke
app:backgroundTint
atribut tombol :Hasil Visual:
Diedit: (untuk mengatasi masalah acara sentuh)
Dari sudut pandang keseluruhan, aliran acara sentuh dimulai dari
Activity
, kemudian mengalir ke tata letak (dari induk ke tata letak anak), lalu ke tampilan. (LTR mengalir dalam gambar berikut)Ketika acara sentuhan mencapai pandangan sasaran, pandangan dapat menangani acara tersebut kemudian memutuskan untuk lulus ke sebelumnya layout / kegiatan atau tidak (kembali
false
daritrue
dalamonTouch
metode). (Aliran RTL pada gambar di atas)Sekarang mari kita lihat View 's kode sumber untuk mendapatkan wawasan yang lebih dalam sentuhan acara mengalir. Dengan melihat implementasi dari
dispatchTouchEvent
, kita akan melihat bahwa jika Anda mengaturOnTouchListener
tampilan dan kemudian kembalitrue
dalamonTouch
metodenya,onTouchEvent
tampilan tidak akan dipanggil.Sekarang, lihat
onTouchEvent
metode di mana tindakan itu beradaMotionEvent.ACTION_UP
. Kami melihat bahwa tindakan melakukan-klik terjadi di sana. Jadi, kembalitrue
diOnTouchListener
'sonTouch
dan akibatnya tidak memanggilonTouchEvent
, menyebabkan tidak memanggilOnClickListener
' sonClick
.Ada masalah lain dengan tidak memanggil
onTouchEvent
, yang terkait dengan keadaan ditekan dan Anda sebutkan dalam pertanyaan. Seperti yang dapat kita lihat di blok kode di bawah ini, ada sebuah instance dariUnsetPressedState
panggilan itu ketika dijalankan. Hasil dari tidak menelepon adalah bahwa tampilan macet dalam keadaan tertekan dan gambar yang dapat ditarik tidak berubah.setPressed
(false)
setPressed(false)
UnsetPressedState :
Mengenai uraian di atas, Anda dapat mengubah kode dengan memanggil
setPressed(false)
diri Anda untuk mengubah status yang dapat digambar di mana tindakan tersebut beradaMotionEvent.ACTION_UP
:sumber
Now, look at the onTouchEvent method where the event action is MotionEvent.ACTION_UP. We see that perform-click action happens there. So, returning true in the OnTouchListener's onTouch and consequently not calling the onTouchEvent, causes not calling the OnClickListener's onClick.
Dalam kasus saya onClick dipanggil. mUnsetPressedState memeriksa apakah itu nol sebelum disetel ke false dan juga runnable tidak yakin untuk berjalan jika kita melakukan prapengaturan. Saya tidak begitu mengerti bagaimana Anda menyimpulkan bahwa itu harus disetel ke salahonClick
disebut karena Anda panggilv.performClick();
. Silakan periksa kode di atas padaMotionEvent.ACTION_UP
bagian lagi,setPressed(false)
dipanggil pula, apakahmUnsetPressedState
itu nol atau tidak, apakahprepressed
benar atau tidak. Perbedaannya terletak pada cara meneleponsetPressed(false)
yang bisa melaluipost
/postDelayed
atau langsung.Anda mengacau
touch
danfocus
acara. Mari kita mulai dengan memahami perilaku dengan warna yang sama. Secara default, ada yangSelector
ditetapkan sebagai latar belakangButton
di Android. Jadi cukup mengubah warna latar belakang, make adalah statis (warna tidak akan berubah). Tapi itu bukan perilaku asli.Selector
mungkin terlihat seperti ini.Seperti yang Anda lihat di atas, ada negara bagian
focused
dan negara bagianpressed
. Dengan pengaturanonTouchListener
Anda akan menangani acara sentuh, yang tidak ada hubungannya denganfocus
.Selector
Tombol harus menggantikanfocus
acara dengantouch
selama acara klik pada tombol. Tetapi pada bagian pertama dari kode Anda, Anda mencegat acara untuktouch
(mengembalikan true from callback). Perubahan warna tidak dapat dilanjutkan lebih lanjut dan membeku dengan warna yang sama. Dan itulah mengapa varian kedua (tanpa intersepsi) berfungsi dengan baik dan itu adalah kebingungan Anda.MEMPERBARUI
Yang perlu Anda lakukan hanyalah mengubah perilaku dan warna untuk
Selector
. Misalnya dengan menggunakan latar belakang berikutnya untukButton
. DAN hapus sama sekalionTouchListener
dari implementasi Anda.sumber
onTouchListener
Anda inginkan. Anda tidak perlu mengkonsumsi acara, olehreturn true
.backgroundColor
.jika Anda menetapkan latar belakang tombol, itu tidak akan mengubah warna saat klik.
dan atur sebagai backgrount ke tombol Anda
sumber
Anda bisa menggunakan Chips bahan untuk bukan tampilan Tombol. lihat: https://material.io/develop/android/components/chip di sana mereka menangani acara-acara hililghted dan Anda dapat menyesuaikan dengan menerapkan tema.
sumber