Dokunmatik etkinlikleri
ViewGroup
özel ilgi gösteriyor
çünkü ViewGroup
için farklı hedeflerin çocukları olması yaygın bir durumdur.
etkinlikleri ViewGroup
için farklıdır. Her görüntülemenin
bunun için tasarlanmış dokunma etkinliklerini,
onInterceptTouchEvent()
.
yöntemidir.
Aşağıdaki ilgili kaynaklara bakın:
ViewGroup'taki dokunma etkinliklerine müdahale etme
onInterceptTouchEvent()
yöntemi, cihazda bir dokunma etkinliği algılandığında
, alt yüzeyleri de dahil olmak üzere bir ViewGroup
yüzeyinde. Eğer
onInterceptTouchEvent()
, true
değerini döndürür.
MotionEvent
yakalanır. Yani bu durum çocuğa değil,
onTouchEvent()
yöntemini kullanın.
onInterceptTouchEvent()
yöntemi, anne veya babanıza dokunma etkinliklerini görme fırsatı verir.
kontrol etmesi gerekir. onInterceptTouchEvent()
satıcısından true
iade ederseniz
daha önce dokunma etkinliklerini işleyen alt görünüm,
ACTION_CANCEL
,
ve o andan itibaren gerçekleşen etkinlikler, ebeveynin onTouchEvent()
yöntemine gönderilir
bir e-posta alırsınız. onInterceptTouchEvent()
, false
ve
görünüm hiyerarşisinden normal hedeflerine doğru ilerlerken etkinlikleri
ona ait onTouchEvent()
olan etkinlik.
Aşağıdaki snippet'te MyViewGroup
sınıfı, ViewGroup
öğesini genişletiyor.
MyViewGroup
birden fazla alt görünüm içeriyor. Parmağınızı bir çocuk görünümü üzerinde sürüklerseniz
alt görünüm artık dokunma etkinliklerini almaz ve MyViewGroup
dokunma işlemini gerçekleştirir
etkinliklerini görürsünüz. Bununla birlikte, çocuk görünümündeki düğmelere dokunur veya alt öğeyi kaydırırsanız
dikey olarak görüntülediğinde, alt öğe kastedildiği için bu dokunma etkinliklerine müdahale etmez.
hedefi belirleyebilirsiniz. Böyle durumlarda onInterceptTouchEvent()
, false
değerini döndürür ve
MyViewGroup
sınıfın onTouchEvent()
numarası aranmıyor.
Kotlin
class MyViewGroup @JvmOverloads constructor( context: Context, private val mTouchSlop: Int = ViewConfiguration.get(context).scaledTouchSlop ) : ViewGroup(context) { ... override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { // This method only determines whether you want to intercept the motion. // If this method returns true, onTouchEvent is called and you can do // the actual scrolling there. return when (ev.actionMasked) { // Always handle the case of the touch gesture being complete. MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> { // Release the scroll. mIsScrolling = false false // Don't intercept the touch event. Let the child handle it. } MotionEvent.ACTION_MOVE -> { if (mIsScrolling) { // You're currently scrolling, so intercept the touch event. true } else { // If the user drags their finger horizontally more than the // touch slop, start the scroll. // Left as an exercise for the reader. val xDiff: Int = calculateDistanceX(ev) // Touch slop is calculated using ViewConfiguration constants. if (xDiff > mTouchSlop) { // Start scrolling! mIsScrolling = true true } else { false } } } ... else -> { // In general, don't intercept touch events. The child view // handles them. false } } } override fun onTouchEvent(event: MotionEvent): Boolean { // Here, you actually handle the touch event. For example, if the action // is ACTION_MOVE, scroll this container. This method is only called if // the touch event is intercepted in onInterceptTouchEvent. ... } }
Java
public class MyViewGroup extends ViewGroup { private int mTouchSlop; ... ViewConfiguration vc = ViewConfiguration.get(view.getContext()); mTouchSlop = vc.getScaledTouchSlop(); ... @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // This method only determines whether you want to intercept the motion. // If this method returns true, onTouchEvent is called and you can do // the actual scrolling there. final int action = MotionEventCompat.getActionMasked(ev); // Always handle the case of the touch gesture being complete. if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { // Release the scroll. mIsScrolling = false; return false; // Don't intercept touch event. Let the child handle it. } switch (action) { case MotionEvent.ACTION_MOVE: { if (mIsScrolling) { // You're currently scrolling, so intercept the touch event. return true; } // If the user drags their finger horizontally more than the // touch slop, start the scroll. // Left as an exercise for the reader. final int xDiff = calculateDistanceX(ev); // Touch slop is calculated using ViewConfiguration constants. if (xDiff > mTouchSlop) { // Start scrolling. mIsScrolling = true; return true; } break; } ... } // In general, don't intercept touch events. The child view handles them. return false; } @Override public boolean onTouchEvent(MotionEvent ev) { // Here, you actually handle the touch event. For example, if the // action is ACTION_MOVE, scroll this container. This method is only // called if the touch event is intercepted in onInterceptTouchEvent. ... } }
ViewGroup
özelliğinin ayrıca bir
requestDisallowInterceptTouchEvent()
yöntemidir. Bir alt öğe, üst öğe ile birlikte kendisini istemediğinde ViewGroup
bu yöntemi çağırır
onInterceptTouchEvent()
ile dokunma etkinliklerine müdahale edecek üst öğeler.
ACTION_OUTSIDE etkinliklerini işle
ViewGroup
,MotionEvent
ACTION_OUTSIDE
,
etkinlik varsayılan olarak alt öğelerine gönderilmez. Bir MotionEvent
öğesini şununla işlemek için:
ACTION_OUTSIDE
, geçersiz kılma
dispatchTouchEvent(MotionEvent event)
uygun View
veya
bunları ilgili
Window.Callback
- şunun için:
örnek, Activity
.
ViewConfiguration sabitlerini kullan
Önceki snippet, bir değişkeni başlatmak için geçerli ViewConfiguration
kodunu kullanır
adı mTouchSlop
. Erişim için ViewConfiguration
sınıfını kullanabilirsiniz
toplam mesafeleri, hızları ve süreleri görebilirsiniz.
"Dokunma eğimi" kullanıcının dokunuşunun, hareket başlamadan önce gidebileceği mesafeyi piksel cinsinden ifade eder kaydırma olarak yorumlanır. Dokunmatik eğim, genellikle kullanıcı aşağıdaki işlemleri yaparken yanlışlıkla ekranı kaydırmayı önlemek için kullanılır. ekrandaki öğelere dokunma gibi başka bir dokunma işlemi gerçekleştiriyor.
Yaygın olarak kullanılan diğer iki ViewConfiguration
yöntemi,
getScaledMinimumFlingVelocity()
ve
getScaledMaximumFlingVelocity()
.
Bu yöntemler, ölçülen bir hızla fiske başlatmak için sırasıyla minimum ve maksimum hızı döndürür.
piksel/saniye. Örnek:
Kotlin
private val vc: ViewConfiguration = ViewConfiguration.get(context) private val mSlop: Int = vc.scaledTouchSlop private val mMinFlingVelocity: Int = vc.scaledMinimumFlingVelocity private val mMaxFlingVelocity: Int = vc.scaledMaximumFlingVelocity ... MotionEvent.ACTION_MOVE -> { ... val deltaX: Float = motionEvent.rawX - mDownX if (Math.abs(deltaX) > mSlop) { // A swipe occurs, do something. } return false } ... MotionEvent.ACTION_UP -> { ... if (velocityX in mMinFlingVelocity..mMaxFlingVelocity && velocityY < velocityX) { // The criteria are satisfied, do something. } }
Java
ViewConfiguration vc = ViewConfiguration.get(view.getContext()); private int mSlop = vc.getScaledTouchSlop(); private int mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); private int mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); ... case MotionEvent.ACTION_MOVE: { ... float deltaX = motionEvent.getRawX() - mDownX; if (Math.abs(deltaX) > mSlop) { // A swipe occurs, do something. } ... case MotionEvent.ACTION_UP: { ... } if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity && velocityY < velocityX) { // The criteria are satisfied, do something. } }
Çocuk görünümünün dokunulabilir alanını genişletme
Android, kullanıcıları
TouchDelegate
sınıf var
bir ebeveynin, alt görüntülemedeki dokunulabilir alanı çocuğun sınırlarının ötesine taşıması mümkün olur. Bu
çocuğun küçük olması ancak daha geniş bir dokunma bölgesine ihtiyacı olduğunda kullanışlıdır. Ayrıca şunu da kullanabilirsiniz:
çocuğun dokunulacağı bölgeyi daraltmaya
çalışacak.
Aşağıdaki örnekte,
ImageButton
, yetki verilmiş kullanıcıdır
view_, yani ebeveynin dokunma alanını genişlettiği alt öğedir. Düzen dosyası şu şekildedir:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parent_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <ImageButton android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null" android:src="@drawable/icon" /> </RelativeLayout>
Aşağıdaki snippet şu görevleri tamamlar:
- Üst görünümü alır ve bir
Runnable
yayınlar kullanıcı arayüzü iş parçacığı. Bu, ebeveynin, çağrıyı yapmadan önce alt öğelerini yerleştirmesini sağlar.getHitRect()
. yöntemidir.getHitRect()
yöntemi, alt yayıncının isabet dikdörtgenini (veya dokunulabilir alan) ebeveynin koordinatlarında yer alır. ImageButton
alt görünümünü bulur ve almak içingetHitRect()
öğesini çağırır çocukların dokunulabilir alanının sınırlarını aşabilir.ImageButton
alt görünümünün isabet dikdörtgeninin sınırlarını genişletir.- Genişletilmiş isabet dikdörtgeninden ve
TouchDelegate
Parametre olarakImageButton
alt görünüm. - Üst görünümde
TouchDelegate
öğesini, dokunma yetkisinin içindeki dokunmalarla dokunacak şekilde ayarlar sınırlar alt öğeye yönlendirilir.
ImageButton
alt görünümü için dokunma yetkisi olarak üst görünüm kapasitesinde
Tüm dokunma etkinliklerini alır. Dokunma etkinliği, alt yayıncının isabet dikdörtgeninde gerçekleşirse üst öğe
, dokunma etkinliğini işlenmek üzere çocuğa iletir.
Kotlin
public class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Post in the parent's message queue to make sure the parent lays out // its children before you call getHitRect(). findViewById<View>(R.id.parent_layout).post { // The bounds for the delegate view, which is an ImageButton in this // example. val delegateArea = Rect() val myButton = findViewById<ImageButton>(R.id.button).apply { isEnabled = true setOnClickListener { Toast.makeText( this@MainActivity, "Touch occurred within ImageButton touch region.", Toast.LENGTH_SHORT ).show() } // The hit rectangle for the ImageButton. getHitRect(delegateArea) } // Extend the touch area of the ImageButton beyond its bounds on the // right and bottom. delegateArea.right += 100 delegateArea.bottom += 100 // Set the TouchDelegate on the parent view so that touches within // the touch delegate bounds are routed to the child. (myButton.parent as? View)?.apply { // Instantiate a TouchDelegate. "delegateArea" is the bounds in // local coordinates of the containing view to be mapped to the // delegate view. "myButton" is the child view that receives // motion events. touchDelegate = TouchDelegate(delegateArea, myButton) } } } }
Java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Get the parent view. View parentView = findViewById(R.id.parent_layout); parentView.post(new Runnable() { // Post in the parent's message queue to make sure the parent lays // out its children before you call getHitRect(). @Override public void run() { // The bounds for the delegate view, which is an ImageButton in // this example. Rect delegateArea = new Rect(); ImageButton myButton = (ImageButton) findViewById(R.id.button); myButton.setEnabled(true); myButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "Touch occurred within ImageButton touch region.", Toast.LENGTH_SHORT).show(); } }); // The hit rectangle for the ImageButton. myButton.getHitRect(delegateArea); // Extend the touch area of the ImageButton beyond its bounds on // the right and bottom. delegateArea.right += 100; delegateArea.bottom += 100; // Instantiate a TouchDelegate. "delegateArea" is the bounds in // local coordinates of the containing view to be mapped to the // delegate view. "myButton" is the child view that receives // motion events. TouchDelegate touchDelegate = new TouchDelegate(delegateArea, myButton); // Set the TouchDelegate on the parent view so that touches // within the touch delegate bounds are routed to the child. if (View.class.isInstance(myButton.getParent())) { ((View) myButton.getParent()).setTouchDelegate(touchDelegate); } } }); } }