ViewPager in ListView-Zeile verhindert, dass onItemClick gefeuert wird

Ich habe einen ViewPager in jeder Zeile eines ListView. Es funktioniert gut, es ändert die Ansichten in ihm, wenn der Benutzer die Swipe-Geste verwendet, aber es verhindert, dass die ListView's onItemClick-Methode aufgerufen wird. Ich weiß, dass der ViewPager der Schuldige ist, denn wenn ich ihn verstecke, wird der OnItemClick angerufen, also das ist es, was ich versuche:

Ich habe eine ViewGroup erstellt, um die Zeile (RowView) zu sein. Diese ViewGroup hat onInterceptTouchEvent overriden, um den ViewPager zu vermeiden, um weitere Touch-Events zu behandeln, wenn ich einen Klick erkenne. Aber der OnItemClick-Rückruf wird noch nicht aufgerufen. Und der Listenauswahl wird weder bei Klick noch angezeigt. Ich möchte, dass diese beiden Funktionen funktionieren.

  • Phonegap App mit Smart Card Integration
  • Bewegen Sie ein LatLng 5 Meter zu einem anderen LatLng
  • Wie man Text innerhalb eines Knopfes animiert
  • Android Glide: Wie kann ich Bitmaps herunterladen und zwischenspeichern?
  • Android-ASync-Task ProgressDialog wird nicht angezeigt, bis der Hintergrund-Thread beendet ist
  • Wie kann ich ein Ereignis auslösen, wenn der Klick außerhalb eines Dialogs erfolgt
  • So sieht das onInterceptTouchEvent von RowView aus wie:

     @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int actionMasked = ev.getActionMasked(); switch(actionMasked) { case MotionEvent.ACTION_DOWN: Log.d("RowView", "OnInterceptTouchEvent - Down"); tapDetector.onTouchEvent(ev); return false; case MotionEvent.ACTION_CANCEL: Log.d("RowView", "OnInterceptTouchEvent - Cancel"); tapDetector.onTouchEvent(ev); break; case MotionEvent.ACTION_UP: if(tapDetector.onTouchEvent(ev)) { Log.d("RowView", "OnInterceptTouchEvent - UP!"); return true; } break; } return super.onInterceptTouchEvent(ev); } 

    Irgendwelche Vorschläge, dies zu lösen?

    EDIT : Kein Beispiel dafür, wie das onItemClick in MainActivity nicht aufgerufen wird, wenn der ViewPager aktiv ist (Lollipop list selector erscheint auch nicht)

    Hauptaktivität

     ListView listView = (ListView) findViewById(R.id.main_list); listView.setAdapter(new MainListAdapter(this, 30)); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.d(TAG, "onItemClick: " + position); } }); 

    Listenelement XML:

     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="80dp" android:descendantFocusability="blocksDescendants" > <TextView android:id="@+id/row_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <android.support.v4.view.ViewPager android:id="@+id/row_viewpager" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="visible" /> </RelativeLayout> 

    Listenadapter:

     public class MainListAdapter extends BaseAdapter { private Context context; private LayoutInflater inflater; private int count; public MainListAdapter(Context context, int count) { this.context = context; this.inflater = LayoutInflater.from(context); this.count = count; } @Override public int getCount() { return count; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null) { holder = new ViewHolder(); convertView = createRow(parent, holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.textView.setText(Integer.toString(position)); int randomPages = (int) (new Random().nextDouble()*5+2); holder.viewPager.setAdapter(new NumAdapter(context, randomPages)); return convertView; } private View createRow(ViewGroup parent, ViewHolder holder) { View view = inflater.inflate(R.layout.row_main_listview, parent, false); holder.textView = (TextView) view.findViewById(R.id.row_num); holder.viewPager = (ViewPager) view.findViewById(R.id.row_viewpager); view.setTag(holder); return view; } private static class ViewHolder { public TextView textView; public ViewPager viewPager; } } 

    ViewPager's Adapter:

     public class NumAdapter extends PagerAdapter { private LayoutInflater inflater; private int count; public NumAdapter(Context context, int count) { this.inflater = LayoutInflater.from(context); this.count = count; } @Override public Object instantiateItem(ViewGroup container, int position) { TextView textView = (TextView) inflater.inflate(R.layout.page_viewpager, container, false); textView.setText("Page " + position); container.addView(textView); return textView; } @Override public int getCount() { return count; } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View)object); } } 

  • Benutzerdefinierte gerenderten Android App-Widget
  • Wie man eine einfache asynchische Aufgabe mit Volley-Bibliothek Android zu tun
  • Android: Verwenden Sie einen datepicker und timepicker aus einem Dialog
  • So erhalten Sie Berechnungszeit in NDK
  • Caching im Android-Webview
  • Verwenden Sie Abmessungen im benutzerdefinierten Stil
  • 9 Solutions collect form web for “ViewPager in ListView-Zeile verhindert, dass onItemClick gefeuert wird”

    Ich denke besser, überschreibe Listenansicht auf Interceptor als Viewgroup.

    TouchEvent Flow einfach:

    Acitivity Touch Event -> Viewgroup.dispatchtouchevent -> viewgroup.intercepter ..-> view.dispatchtouch … -> …..

    In diesem Fall list.dispatch call. ViewPager.dispatch Ereignis zu ViewPager.dispatch . Aber vor ViewPager.dispatchtouchevent , rufen Sie ListView.intercepterTouchEvent .

    Wenn dispatchTouchEvent false Anruf TouchEvent ,

    Wenn intercepterTouchEvent zurückkehren true rufen Sie nicht kind dispatchTouchEvent aber geben Sie false calling child dispatchTouchEvent . So listview.intercepterTouchEvent return true , Aufruf o nItemClick .

    listView.intercepterTouchEvent wenn listView.intercepterTouchEvent true zurückgibt, nicht swiped viewPager Items.

    Sie können die Aktion des Benutzers wischen oder klicken Sie auf 2-Wege. TouchEvent und guesturedetector ..

    In listview's IntercepterTouchEvent(Event ev);

     VelocityTracker mVelocityTracker; PointF mLastPoint; public mListView(Context context) { super(context); init(); } public mListView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public mListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init(){ mLastPoint = new PointF(); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if(mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(ev); switch (ev.getAction()){ case MotionEvent.ACTION_MOVE: mVelocityTracker.computeCurrentVelocity(100); int x = (int)Math.abs(mVelocityTracker.getXVelocity()); int move_x = (int)Math.abs(ev.getX() - mLastPoint.x); Log.d("ListView","speed : " + x +" move_x : " + move_x); //here x is drag speed. (pixel/s) // change value left right both value you want speed and move amount if(move_x < 100 || x <100) { mLastPoint.set(ev.getX(), ev.getY()); return true; } break; case MotionEvent.ACTION_DOWN: mLastPoint.set(ev.getX(), ev.getY()); break; case MotionEvent.ACTION_UP: mVelocityTracker.recycle();mVelocityTracker = null; break; } return super.onInterceptTouchEvent(ev); } 

    Sie können Geschwindigkeit um 100 bewegen oder um 100 Pixel bewegen. Wenn nicht Click-Event durchgeführt wird.

    Ich hoffe, dieser Text kann dir helfen ……

    Und füge noch einen Codeschlag hinzu.

     @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if(mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(ev); switch (ev.getAction()){ case MotionEvent.ACTION_MOVE: mVelocityTracker.computeCurrentVelocity(10); int x = (int)Math.abs(mVelocityTracker.getXVelocity()); int move_x = (int)Math.abs(ev.getX() - mLastPoint.x); int move_y = (int)Math.abs(ev.getY() - mLastPoint.y); Log.d("ListView","speed : " + x +" move_x : " + move_x + " move_y : "+ move_y); if(move_x < move_y || x < 10) { mLastPoint.set(ev.getX(), ev.getY()); return true; }else if(move_x > move_y){ return false; } break; case MotionEvent.ACTION_DOWN: mLastPoint.set(ev.getX(), ev.getY()); break; case MotionEvent.ACTION_UP: break; } return super.onInterceptTouchEvent(ev); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("ListView", "dispatch"); switch (ev.getAction()){ case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_UP: if(mVelocityTracker != null){mVelocityTracker.recycle();mVelocityTracker = null;} break; } return super.dispatchTouchEvent(ev);; } 

    Wie dein Viewpaper ist dein Listview Kind, seine verbrauchen die Touch-Events. Sie können dies verhindern, indem Sie Ihre Viewpagers Kind unclickable, dh

      TextView textView =(TextView)inflater.inflate(R.layout.page_viewpager,container, false); textView.setText("Page " + position); textView.setClickable(false); 

    Ich würde vorschlagen, OnClickListener auf jeder ViewPager Instanz selbst zu setzen und die Verwendung von onItemClickListener der ListView zu vermeiden. Du kannst dann auch onInterceptTouchEvent() komplett entfernen. Das wäre die einfachste und stabile Lösung. Weniger Code – weniger Bugs;)

    Sie müssen eine der folgenden Aktionen ausführen:

    Setzen Sie einen setOnClickListener auf das Kind des Viewpager oder finden Sie

     android:descendantFocusability="beforeDescendants" 

    Ich hoffe das kann dir helfen.

    Ich denke, das sollte der Trick machen.

     viewPager.getParent().requestDisallowInterceptTouchEvent(false); 

    Ich hoffe das wird dir helfen.

    Die Idee ist, den Klick-Listener auf dem View-Pager zu machen und nicht die ListView

    Wenn Sie den ViewPager in der getView-Methode hinzufügen, setzen Sie den Tag auf die Position der Zeile

     holder.viewPager.setTag(position); 

    Dann füge den Klick-Listener zum ViewPager hinzu (auch in getView)

     viewPager.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { int position = v.getTag(); Log.d(TAG, "onItemClick: " + position); //Fire a delegate or notification of whatever you want to do on the item click. You now have the position myClickListener.onItemClicked(position); } }); 

    Das Problem ist mit dem Listenadapter Viewer. Ich hatte ein ähnliches Problem, als ich versuchte, das gleiche Feature (Viewpager in einer Listview-Zeile) zu implementieren. Ich habe es gelöst, indem ich dies mache —- Setzen Sie den onclicklistener auf viewholder Objekt anstatt, auf Listenansicht direkt zu setzen. Um dies zu tun, müssen Sie onitemclicklistener auf Ihrer Adapterklasse implementieren.

    Eine Verbesserung gegenüber Adrians Antwort:

     public class CustomListView extends ListView { private GestureDetector gestureDetector; public CustomListView(Context context) { super(context); gestureDetector = new GestureDetector(context, new CustomListViewOnGestureListener()); } public CustomListView(Context context, AttributeSet attrs) { super(context, attrs); gestureDetector = new GestureDetector(context, new CustomListViewOnGestureListener()); } public CustomListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); gestureDetector = new GestureDetector(context, new CustomListViewOnGestureListener()); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public CustomListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); gestureDetector = new GestureDetector(context, new CustomListViewOnGestureListener()); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { gestureDetector.onTouchEvent(ev); return super.dispatchTouchEvent(ev); } private class CustomListViewOnGestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onSingleTapUp(MotionEvent ev) { int firstVisiblePosition = getFirstVisiblePosition(); int itemPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); int childIndex = itemPosition - firstVisiblePosition; View view = getChildAt(childIndex); performItemClick(view, itemPosition, getItemIdAtPosition(itemPosition)); return true; } } } 

    Dies ist, was ich endlich geschafft habe, dies zu tun, obwohl der Listenwähler nicht funktioniert. Dies könnte verbessert werden, aber für jetzt ist es die einzige Problemumgehung, die ich mag, wie es funktioniert.

     public class CustomListView extends ListView implements AbsListView.OnScrollListener { /* * Used for detect taps */ private GestureDetector tapDetector; /* * As we need to set our own OnScrollListener, this stores the one * used outside, if any */ private OnScrollListener onScrollListener; private boolean isScrolling = false; public CustomListView(Context context) { super(context); initView(context); } public CustomListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public CustomListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public CustomListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initView(context); } private void initView(Context context) { tapDetector = new GestureDetector(context, new TapListener()); super.setOnScrollListener(this); } @Override public void setOnScrollListener(OnScrollListener onScrollListener) { this.onScrollListener = onScrollListener; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean isTap = tapDetector.onTouchEvent(ev); if(ev.getActionMasked() == MotionEvent.ACTION_UP) { // Don't perform the click if the ListView is scrolling // so it is able to stop the scroll if(isTap && !isScrolling && hasOnItemClickListener()) { int itemPosition = pointToPosition((int)ev.getX(), (int)ev.getY()); performItemClick(this, itemPosition, getItemIdAtPosition(itemPosition)); } } return super.dispatchTouchEvent(ev); } public boolean hasOnItemClickListener() { return getOnItemClickListener() != null; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { isScrolling = scrollState != OnScrollListener.SCROLL_STATE_IDLE; if(this.onScrollListener != null) { onScrollListener.onScrollStateChanged(view, scrollState); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if(this.onScrollListener != null) { onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } } 
    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.