2011-11-14 173 views
3

我有一個畫廊,其適配器創建多個實例的LinearLayout一個畫廊。那些線性佈局實例有按鈕,然而,當有人點擊按鈕時,他們不能拖動畫廊。滾動的按鈕

我的想法是具有用戶可以通過滾動菜單。通常使用ScrollView完成的事情,但是因爲我希望滾動的視圖能夠「捕捉」到當前的按鈕頁面,所以一個Gallery可以更好地工作。

這個問題是類似這樣的:Android gallery of LinearLayouts

然而,當我已經解決了「按鈕會出現點擊」拖動問題的時候,我似乎無法讓有它的工作就像一個滾動型呢,這些按鈕可用作拖動區域的一部分。

任何提示?

不知道,如果代碼是相關的,但在這裏它是。

佈局包含畫廊:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

     <Gallery 
      android:id="@+id/gallery" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" android:fadingEdge="none" 
      android:spacing="0dp"/> 

</FrameLayout> 

測試的活動,填充畫廊:

import com.zehfernando.display.widgets.ZGallery; 

public class ScrollTestActivity extends Activity { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.scrolltest); 

     Gallery gallery = (Gallery) findViewById(R.id.gallery); 
     gallery.setAdapter(new LayoutAdapter(this)); 
    } 

    public class LayoutAdapter extends BaseAdapter { 
     private Context mContext; 

     public LayoutAdapter(Context c) { 
      mContext = c; 
     } 

     public int getCount() { 
      return 3; 
     } 

     public Object getItem(int position) { 
      return position; 
     } 

     public long getItemId(int position) { 
      return position; 
     } 

     public View getView(int position, View convertView, ViewGroup parent) { 
      LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      View v = vi.inflate(R.layout.scrolllayout, null); 
      v.setMinimumWidth(getWindowManager().getDefaultDisplay().getWidth()); 
      return v; 
     } 
    } 
} 

該畫廊裏面去的框架佈局:

<?xml version="1.0" encoding="utf-8"?> 
<com.zehfernando.display.widgets.ScrollableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <Button 
     android:id="@+id/buttonRegister" 
     android:layout_width="200dp" 
     android:layout_height="72dp" 
     android:text="REGISTER"/> 

    <Button 
     android:id="@+id/buttonUnregister" 
     android:layout_width="match_parent" 
     android:layout_height="72dp" 
     android:text="UNREGISTER" /> 

</com.zehfernando.display.widgets.ScrollableLinearLayout> 

「ScrollableLinearLayout」就是我的類,它擴展了LinearLayout來覆蓋onPressed。

回答

10

好吧,我想我得到了它,所以這裏是萬一有人運行到這個在未來。

我不知道觸摸事件是如何沿着顯示列表傳播的,所以這比我想承認的花費了更多的試驗和錯誤,但基本上:可以在父母上攔截觸摸事件,而不是讓它傳播到孩子,基本上打開按鈕沒用(允許用戶點擊並拖動它,將事件發送給母公司onTouchEvent代替)。這是通過onInterceptTouchEvent方法完成的。

因此,而不是有Gallery的,我已經擴展它(調用它現在ZGallery)。這足以使包含按鈕沒用:

@Override 
public boolean onInterceptTouchEvent(MotionEvent __e) { 
    return true; 
} 

當然不過,我想,以確保該按鈕工作(他們是點擊),同時也允許拖累。

有可能是一個更聰明的方式來做到這一點,但我做的是攔截在我的新畫廊(如上)的觸摸事件,但允許它要經過(返回false),直到用戶移動了'光標'按給定的閾值 - 然後我將其解釋爲拖動意圖,開始正確攔截觸摸事件。這會導致觸摸事件發送到我自己的畫廊,按預期工作。

您可以對其進行修改,使其僅適用於垂直或水平拖動。

所以無論如何,這是一個Gallery類,允許任何元素上拖動它裏面的一個簡化版本:

public class ZGallery extends Gallery { 

    // Constants 
    protected static final float DRAG_THRESHOLD = 10; // If dragging for more than this amount of pixels, means it's a scroll 

    // Properties 
    protected boolean isPressed; 
    protected float startPressX; 
    protected float startPressY; 
    protected boolean isDragging; 

    // ================================================================================================================ 
    // CONSTRUCTOR ---------------------------------------------------------------------------------------------------- 

    public ZGallery(Context context) { 
     this(context, null); 
    } 

    public ZGallery(Context context, AttributeSet attrs) { 
     this(context, attrs, R.attr.galleryStyle); 
    } 

    public ZGallery(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    // ================================================================================================================ 
    // EVENT INTERFACE ------------------------------------------------------------------------------------------------ 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent __e) { 
     // Intercepts all touch screen motion events. This allows you to watch events as they are dispatched to your children, and take ownership of the current gesture at any point. 
     // Return true to steal motion events from the children and have them dispatched to this ViewGroup through onTouchEvent(). 
     // The current target will receive an ACTION_CANCEL event, and no further messages will be delivered here. 

     //return super.onInterceptTouchEvent(__e); // super always returns false 

     // If this function returns TRUE, NO children get dragging events. This only happens 
     // the first interception (mouse down); if true is returned, nothing is intercepted anymore, and 
     // events are passed to onTouchEvent directly. 
     // If FALSE is returned, this may be called again, but only if there's a children receiving the 
     // events instead of this. 
     // In sum, once onTouchEvent is called here, onInterceptTouchEvent is not called anymore. 

     // Interprets drag data 
     return evaluateTouchEvent(__e); 

    } 

    @Override 
    public boolean onTouchEvent(MotionEvent __e) { 
     // Interprets drag data 
     evaluateTouchEvent(__e); 

     // Properly lets superclass interpret touch events (for dragging, fling, etc) 
     return super.onTouchEvent(__e); 
    } 

    protected boolean evaluateTouchEvent(MotionEvent __e) { 
     // Interprets motion to see if the user is dragging the View 
     // This will run in parallel with the children events 
     float dragDeltaX; 
     float dragDeltaY; 

     switch (__e.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
       // Pressing... 
       isPressed = true; 
       startPressX = __e.getX(); 
       startPressY = __e.getY(); 
       break; 
      case MotionEvent.ACTION_MOVE: 
       // Moving... 
       if (isPressed && !isDragging) { 
        dragDeltaX = __e.getX() - startPressX; 
        dragDeltaY = __e.getY() - startPressY; 

        if (Math.abs(dragDeltaX) > DRAG_THRESHOLD || Math.abs(dragDeltaY) > DRAG_THRESHOLD) { 
         // Moved too far, means it's dragging! 

         // Inject click from correct position so superclass code knows where to drag from 
         MotionEvent me = MotionEvent.obtain(__e); 
         me.setAction(MotionEvent.ACTION_DOWN); 
         me.setLocation(__e.getX() - dragDeltaX, __e.getY() - dragDeltaY); 
         super.onTouchEvent(me); 

         isDragging = true; 
        } 
       } 
       break; 
      case MotionEvent.ACTION_UP: 
       // Releasing... 
       if (isPressed) { 
        isPressed = false; 
        // Let go while pressed 
        if (isDragging) { 
         // Was dragging, so just go back 
         isDragging = false; 
        } else { 
         // Was not dragging, this will trigger a click 
        } 
       } 
       break; 
     } 


     // If not dragging, event should be passed on 
     // If dragging, the event should be intercepted and interpreted by this gallery's onTouchEvent instead 
     return isDragging; 
    } 
} 

它似乎運作良好。希望這會對別人有所幫助!

+0

夥計,即時通訊新的android ...如何在主要活動中實現此代碼? – jayellos

+0

謝謝澤西,救了我的屁股! – Leo

+0

真的很好......謝謝zeh ... – kalandar