2015-06-24 5 views
6

मैं अपने RecycleView भीतर स्पर्श घटना प्रसार पर नियंत्रण की कोशिश में कुछ समस्या है। तो मैं एक RecyclerView एक कार्ड ढेर नकल CardViews का एक सेट को आबाद करने के लिए है (ताकि वे एक निश्चित विस्थापन के साथ एक दूसरे पर व्याप्त है, हालांकि वे अलग अलग ऊंचाई मूल्य है)। मेरे वर्तमान समस्या प्रत्येक कार्ड एक बटन है कि और रिश्तेदार कार्ड विस्थापन के बाद से बटन यह स्थिति है कि बटन अतिव्यापी हैं और जब भी एक स्पर्श घटना भेजा जाता है यह देखने के पदानुक्रम के नीचे से प्रचार शुरू होता है में परिणाम की ऊंचाई से छोटी है (बच्चों से है उच्चतम बाल संख्या के साथ)।ओवरलैपिंग विचारों के मामले में नियंत्रण स्पर्श घटना प्रचार

लेख मैंने पढ़ा ( this, this और भी this video) स्पर्श प्रचार, इसलिए स्पर्श पहले उच्चतम सूचकांक के साथ बच्चे को वितरित किया जाएगा, माता पिता को ध्यान में रखते दृश्यों का क्रम पर निर्भर है के अनुसार

जब मैं करने के लिए स्पर्श घटना चाहते हैं केवल शीर्ष दृश्य और रीसाइक्लर व्यू के टचबल्स द्वारा संसाधित किया जाना चाहिए (इसे ड्रैग और फ़्लिंग जेस्चर को भी संसाधित करना होगा)। वर्तमान में मैं उन कार्डों के साथ फॉलबैक का उपयोग कर रहा हूं जो गलत बच्चों को छूने से रोकने के लिए माता-पिता के दृश्य पदानुक्रम के भीतर अपनी स्थिति से अवगत हैं लेकिन यह वास्तव में ऐसा करने का बदसूरत तरीका है। मेरे धारणा मैं RecyclerView की dispatchTouchEvent विधि ओवरराइड करने के लिए है और ठीक से केवल सर्वोच्च बच्चे को एक स्पर्श घटना प्रेषण है। हालांकि, जब मुझे लगता है कि ऐसा करने का इस तरह से (जो भी तरह का अनाड़ी है) की कोशिश की:

@Override 
    public boolean dispatchTouchEvent(MotionEvent ev) { 
    View topChild = getChildAt(0); 
    for (View touchable : topChild.getTouchables()) { 
     int[] location = new int[2]; 
     touchable.getLocationOnScreen(location); 
     RectF touchableRect = new RectF(location[0], 
       location[1], 
       location[0] + touchable.getWidth(), 
       location[1] + touchable.getHeight()); 
     if (touchableRect.contains(ev.getRawX(), ev.getRawY())) { 
      return touchable.dispatchTouchEvent(ev); 
     } 
    } 
    return onTouchEvent(ev); 
} 

केवल नीचे घटना बटन के लिए एक कार्ड के भीतर (कोई क्लिक करें घटना शुरू हो रहा) दिया गया था। मैं टच इवेंट प्रोपेगेशन ऑर्डर को रिवर्स करने या किसी विशिष्ट दृश्य में टच इवेंट के प्रतिनिधि पर किसी भी सलाह की सराहना करता हूं। पहले से ही बहुत - बहुत धन्यवाद।

संपादित करें:

public class TestAdapter extends RecyclerView.Adapter { 

List<Integer> items; 

public TestAdapter(List<Integer> items) { 
    this.items = items; 
} 

@Override 
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    View v = LayoutInflater.from(parent.getContext()) 
      .inflate(R.layout.test_layout, parent, false); 
    return new TestHolder(v); 
} 

@Override 
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
    TestHolder currentHolder = (TestHolder) holder; 
    currentHolder.number.setText(Integer.toString(position)); 
    currentHolder.tv.setTag(position); 
    currentHolder.tv.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      int pos = (int) v.getTag(); 
      Toast.makeText(v.getContext(), Integer.toString(pos) + "clicked", Toast.LENGTH_SHORT).show(); 
     } 
    }); 
} 

@Override 
public int getItemCount() { 
    return items.size(); 
} 

private class TestHolder extends RecyclerView.ViewHolder { 

    private TextView tv; 
    private TextView number; 

    public TestHolder(View itemView) { 
     super(itemView); 
     tv = (TextView) itemView.findViewById(R.id.click); 
     number = (TextView) itemView.findViewById(R.id.number); 
    } 

    } 
} 

और एक उदाहरण के कार्ड लेआउट:

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" 
      android:orientation="vertical" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent"> 
<RelativeLayout android:layout_width="match_parent" 
       android:layout_height="match_parent"> 

    <TextView android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:layout_centerInParent="true" 
       android:layout_margin="16dp" 
       android:textSize="24sp" 
       android:id="@+id/number"/> 

    <TextView android:layout_width="wrap_content" 
       android:layout_height="64dp" 
       android:gravity="center" 
       android:layout_alignParentBottom="true" 
       android:layout_alignParentLeft="true" 
       android:layout_margin="16dp" 
       android:textSize="24sp" 
       android:text="CLICK ME" 
       android:id="@+id/click"/> 
</RelativeLayout> 

</android.support.v7.widget.CardView> 

और यह कैसे उदाहरण कार्ड स्टैक Screen

उदाहरण एडाप्टर कोड की तरह लग रही है स्क्रीनशॉट है यहां वह कोड है जिसका उपयोग मैं समस्या को हल करने के लिए अब कर रहा हूं (यह दृष्टिकोण मुझे पसंद नहीं है, मैं बेहतर तरीका ढूंढना चाहता हूं)

public class PositionAwareCardView extends CardView { 

private int mChildPosition; 

public PositionAwareCardView(Context context) { 
    super(context); 
} 

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

public PositionAwareCardView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
} 

public void setChildPosition(int pos) { 
    mChildPosition = pos; 
} 

@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
    // if it's not the topmost view in view hierarchy then block touch events 
    return mChildPosition != 0 || super.onInterceptTouchEvent(ev); 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    return false; 
} 
} 

संपादित करें 2: मैं उल्लेख करने के लिए, इस समस्या को केवल पूर्व Lolipop उपकरणों पर मौजूद है भूल गए हैं, ऐसा लगता है कि Lolipop से शुरू, ViewGroups भी ऊंचाई को ध्यान में स्पर्श घटनाओं भेजने जबकि

संपादित ले 3:

@Override 
protected int getChildDrawingOrder(int childCount, int i) { 
    return childCount - i - 1; 
} 

संपादित: 4: यहाँ मेरे वर्तमान बच्चे चित्रण क्रम है अंत में मैं उपयोगकर्ता यादृच्छिक के लिए समस्या धन्यवाद ठीक करने में सक्षम था, और this answer, समाधान अत्यंत सरल था:

+०१२३५१६४१०६
@Override 
    public boolean dispatchTouchEvent(MotionEvent ev) { 
    if (!onInterceptTouchEvent(ev)) { 
     if (getChildCount() > 0) { 
      final float offsetX = -getChildAt(0).getLeft(); 
      final float offsetY = -getChildAt(0).getTop(); 
      ev.offsetLocation(offsetX, offsetY); 
      if (getChildAt(0).dispatchTouchEvent(ev)) { 
       // if touch event is consumed by the child - then just record it's coordinates 
       x = ev.getRawX(); 
       y = ev.getRawY(); 
       return true; 
      } 
      ev.offsetLocation(-offsetX, -offsetY); 
     } 
    } 
    return super.dispatchTouchEvent(ev); 
} 
+0

क्या आप अपना एक्सएमएल और एडाप्टर –

+0

@war_Hero पोस्ट कर सकते हैं मैंने एक टेस्ट ऐप के लिए कोड जोड़ा है जिसमें एक प्रश्न में वर्णित एक ही समस्या है – Chaosit

उत्तर

2

CardView एल और एल से पहले ऊंचाई एपीआई का उपयोग करता है, यह छाया आकार बदलता है। एल में dispatchTouchEvent जेड आदेश का सम्मान करता है जब बच्चों के जो पूर्व एल

में ऐसा नहीं होता है स्रोत कोड को देखते हुए अधिक पुनरावृत्ति:

पूर्व लॉलीपॉप

ViewGroup#dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev) { 
final boolean customOrder = isChildrenDrawingOrderEnabled(); 
for (int i = childrenCount - 1; i >= 0; i--) { 
    final int childIndex = customOrder ? 
    getChildDrawingOrder(childrenCount, i) : i; 
    final View child = children[childIndex]; 

... 

लॉलीपॉप

ViewGroup#dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev) { 
// Check whether any clickable siblings cover the child 
// view and if so keep track of the intersections. Also 
// respect Z ordering when iterating over children. 

ArrayList<View> orderedList = buildOrderedChildList(); 

final boolean useCustomOrder = orderedList == null 
       && isChildrenDrawingOrderEnabled(); 
final int childCount = mChildrenCount; 
     for (int i = childCount - 1; i >= 0; i--) { 
      final int childIndex = useCustomOrder 
         ? getChildDrawingOrder(childCount, i) : i; 
      final View sibling = (orderedList == null) 
         ? mChildren[childIndex] : orderedList.get(childIndex); 

      // We care only about siblings over the child 
      if (sibling == child) { 
       break; 
      } 
      ... 

बच्चे ड्राइंग आदेश custom child drawing order in a ViewGroup साथ अधिरोहित जा सकता है, और setZ(float) कस्टम जेड दृश्य पर सेट मूल्यों के साथ।

आप custom child drawing order in a ViewGroup देख सकते हैं लेकिन मुझे लगता है कि समस्या के लिए आपका वर्तमान समाधान पर्याप्त है।

+0

उत्तर के लिए धन्यवाद , हां, मैंने पहले से ही बाल ड्राइंग ऑर्डर को ओवरराइड कर दिया है (आप मेरे अंतिम संपादन में कोड देख सकते हैं), क्योंकि प्री-लॉलीपॉप डिवाइस में मुझे गलत बाल प्लेसमेंट में समस्या थी। इसलिए, दुर्भाग्यवश, मैं अब बच्चे ड्राइंग ऑर्डर नहीं बदल सकता, अन्यथा मेरे पास कुछ प्रतिपादन समस्याएं होंगी, इसलिए मैं प्रेषण टचवेन्ट को ओवरराइड करने और टच प्रेषण आदेश को नियंत्रित करने में समाधान ढूंढ रहा था। मुझे अपने वर्तमान समाधान पसंद नहीं हैं, क्योंकि मेरे राय कार्ड में उनकी स्थिति के बारे में पता नहीं होना चाहिए, मैं लेआउटमैनेजर और रीसाइक्लिंग व्यू कक्षाओं में सबकुछ स्थिति से संबंधित होगा। – Chaosit

+0

यह सही है, लेकिन प्री-लॉलीपॉप संस्करण ज़ेड-ऑर्डरिंग का सम्मान नहीं करते हैं, इसलिए ऐसा नहीं लगता कि आप अपने कस्टम कार्यान्वयन के साथ डिफ़ॉल्ट व्यवहार को ओवरराइड करने के अलावा इसके बारे में बहुत कुछ कर सकते हैं, जो आप पहले से ही कर रहे हैं – random

+0

मुझे लगता है कि एक तरीका होना चाहिए 'प्रेषण टचवेन्ट 'को ओवरराइड करने के लिए जो पदानुक्रम को देखने में पहले दृश्य के लिए सख्ती से स्पर्श प्रसार को सीमित कर देगा, दुर्भाग्यवश मेरे अपने प्रयासों ने इस क्षेत्र में बहुत अधिक लाभ नहीं लाया, मैंने ऐसा करने का सबसे कमजोर तरीका किया जिसने प्रेषण स्पर्श कार्यक्रम को बुलाया सबसे ऊपर का बच्चा सीधे, लेकिन मैंने रीसाइक्लर व्यू की स्पर्श प्रतिक्रिया खो दी, इसलिए मैंने शीर्षतम बच्चे में केवल स्पर्श करने के लिए स्पर्श घटनाओं को प्रेषित करने का प्रयास किया, लेकिन मुझे यह अजीब समस्या मिली जब सभी स्पर्श घटनाओं को बटन पर नहीं पहुंचाया गया था (जिसे वर्णित किया गया है प्रश्न) – Chaosit

0

आप क्लिक करने योग्य के रूप में अपने सर्वोच्च दृश्य सेट करने की कोशिश की?

button.setClickable(true); 

यदि यह विशेषता व्यू एक्सएमएल में सेट नहीं है (डिफ़ॉल्ट के रूप में) तो यह क्लिक ईवेंट ऊपर की ओर फैलती है।

लेकिन तुम सर्वोच्च दृश्य पर सेट करता है, तो के रूप में सच है, यह किसी भी अन्य दृश्य पर किसी भी घटना का प्रचार नहीं करना चाहिए।

+0

जब भी आप ऑनक्लिक लिस्टनर को दृश्य पर सेट करते हैं तो क्लिक करने योग्य ध्वज स्वचालित रूप से सेट हो रहा है। मैंने मैन्युअल रूप से ऐसा करने की कोशिश की - इससे मदद नहीं मिली। यह मदद कर सकता है अगर मैं शीर्ष पर छोड़कर प्रत्येक दृश्य के लिए झूठ पर क्लिक करने योग्य सेट करता हूं, लेकिन मूल रूप से यह लगभग उसी समाधान होगा जो मेरे पास अभी है, जबकि मैं स्पर्श घटनाओं के प्रचार को नियंत्रित करने का उचित तरीका खोज रहा हूं – Chaosit

संबंधित मुद्दे