2011-11-14 130 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