希望实现一个离屏的墙(GridView?),用户可以触摸它来移动它

期望的效果我有一堆小图像,我想在“墙”上显示,然后让用户向任何方向扔这个墙,并select一个图像。

最初的想法作为一个可能的实现我在想一个大于屏幕的GridView可以显示 – 但所有使用这个小部件的例子表明,图库不会超出屏幕的大小。

问题什么是最好的部件来实现所需的效果? 代码示例将是特别有益的。

编辑…如果有人有示例代码,可以让我把大约30张图片放在“墙上”(桌子是好的),那么我会接受这个答案。 请注意,“墙”应该看起来像它超出了显示器的边缘,并允许用户使用手指将“墙”向左下拖动。 拖动应该是“自由forms”模式。 在图像上点击一下,就可以检测到callback。 我已经创造了这个解决scheme的赏金。

Solutions Collecting From Web of "希望实现一个离屏的墙(GridView?),用户可以触摸它来移动它"

解决scheme其实很简单,但是很痛苦。 我不得不在我最近做的一个程序中实现这个。 有几个棘手的事情,你必须避开。 必须注意的是,不同的操作系统版本有不同的体验。 需要一定的专业知识或技术来进行这项工作,因为绘图有时会受到这种方法的不利影响。 虽然有一个工作副本,但我提供的代码并不适用于所有人,而且还受到代码中其他更改或自定义的限制。

  • android:layout_width设置为wrap_content
  • android:layout_height设置为wrap_content
  • 在你的代码中:
    • 确定你将有多less行。
    • 将项目数除以行数。
    • 添加gridView。 setStretchMode(NO_STRETCH);
    • 添加gridView。 setNumColumns(列数);
    • 添加gridView。 setColumnWidth(以像素为单位的显式宽度);
  • 滚动:
    • 你可以简单地使用gridView。 在你的onTouchEvent()中的onTouchEvent()

这些是步骤。 所有这些都是为了使其正常工作所必需的。 关键是NO_STRETCH具有特定宽度的显式列数。 如果您需要澄清,可以提供更多细节。 你甚至可以使用VelocityTracker或onFling来处理投掷。 我在我的snappingToPage启用。 使用这个解决scheme,甚至不需要重写onDraw()onLayout() 。 这三行代码摆脱了WebView或任何其他embedded或嵌套的需要。

双向滚动也很容易实现。 这是一个简单的代码解决scheme:

  1. 首先,你的class级开始跟踪两个class级成员的X和Y位置。 还加上状态跟踪;

     // Holds the last position of the touch event (including movement) int myLastX; int myLastY; // Tracks the state of the Touch handling final static private int TOUCH_STATE_REST = 0; final static private int TOUCH_STATE_SCROLLING = 1; int myState = TOUCH_STATE_REST; 
  2. 其次,一定要检查滚动,这样你仍然可以点击或长按图片自己。

     @Override public boolean onInterceptTouchEvent(final MotionEvent ev) {//User is already scrolling something. If we haven't interrupted this already, // then something else is handling its own scrolling and we should let this be. // Once we return TRUE, this event no longer fires and instead all goes to // onTouch() until the next TouchEvent begins (often beginning with ACTION_DOWN). if ((ev.getAction() == MotionEvent.ACTION_MOVE) && (myState != TOUCH_STATE_REST)) return false; // Grab the X and Y positions of the MotionEvent final float _x = ev.getX(); final float _y = ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: final int _diffX = (int) Math.abs(_x - myLastX); final int _diffY = (int) Math.abs(_y - myLastY); final boolean xMoved = _diffX > 0; final boolean yMoved = _diffY > 0; if (xMoved || yMoved) myState = TOUCH_STATE_SCROLLING; break; case MotionEvent.ACTION_DOWN: // Remember location of down touch myLastX = _x; myLastY = _y; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: if (myState == TOUCH_STATE_SCROLLING) // Release the drag myState = TOUCH_STATE_REST; } //If we are not At Rest, start handling in our own onTouch() return myState != TOUCH_STATE_REST; } 
  3. 在GridView知道你正在滚动之后,它会把所有的Touch Events发送到onTouch。 在这里做滚动。

     @Override public boolean onTouchEvent(final MotionEvent ev) { final int action = ev.getAction(); final float x = ev.getX(); final float y = ev.getY(); final View child; switch (action) { case MotionEvent.ACTION_DOWN: //Supplemental code, if needed break; case MotionEvent.ACTION_MOVE: // This handles Scrolling only. if (myState == TOUCH_STATE_SCROLLING) { // Scroll to follow the motion event // This will update the vars as long as your finger is down. final int deltaX = (int) (myLastX - x); final int deltaY = (int) (myLastY - y); myLastX = x; myLastY = y; scrollBy(deltaX, deltaY); } break; case MotionEvent.ACTION_UP: // If Scrolling, stop the scroll so we can scroll later. if (myState == TOUCH_STATE_SCROLLING) myState = TOUCH_STATE_REST; break case MotionEvent.ACTION_CANCEL: // This is just a failsafe. I don't even know how to cancel a touch event myState = TOUCH_STATE_REST; } return true; } 

如果当然,这个解决scheme同时在X和Y上移动。 如果要一次只移动一个方向,可以通过检查X和Y差异的较大值来轻松区分。 (即Math.abs(deltaX) > Math.abs(deltaY) )下面是一个方向滚动的部分样本,但可以在X或Y方向之间切换。

3B。 如果您想一次处理一个方向,请在OnTouch()更改此项:

  case MotionEvent.ACTION_MOVE: if (myState == TOUCH_STATE_SCROLLING) { //This will update the vars as long as your finger is down. final int deltaX = (int) (myLastX - x); final int deltaY = (int) (myLastY - y); myLastX = x; myLastY = y; // Check which direction is the bigger of the two if (Math.abs(deltaX) > Math.abs(deltaY)) scrollBy(deltaX, 0); else if (Math.abs(deltaY) > Math.abs(deltaX)) scrollBy(0, deltaY); // We do nothing if they are equal. } break; 

FuzzicalLogic

一个GridView内容可以超出屏幕的大小,但只能在垂直方向。

问:什么是最好的部件来实现所需的效果?
没有默认的小部件(至less在3.0之前)实现2D滚动。 他们都只实现一维(单向滚动)。 可悲的是,解决您的问题并不容易。

你可以:

  • 在自定义ScrollView类中放置一个TableLayout ,并自己处理触摸事件。 这将允许您进行适当的2D平移,但对于大型数据集不会太好,因为没有视图回收
  • 如果可能,修改GridView以启用水平滚动function(如果可以的话,可能是最好的解决scheme)
  • 尝试把一个TableLayout放在一个ScrollView里面(用layout_width="wrap_content ),放在一个HorizontalScrollView里面 – 虽然这可能工作,但它不会是最佳的解决scheme
  • 用OpenGL做些什么,然后直接画到canvas上 – 这是默认的Gallery 3D应用程序是如何做到的“图片墙”

我认为,唯一的Android本地解决scheme就是拥有一个embedded的WebView,在其中可以拥有二维滚动(并且顺便说一下,这是唯一具有此function的东西)。

按一个图像,你可以通过从JavaScript到JAva的callback来控制行为。

这不是很“漂亮”,但是…这是唯一可行的方式来做你想要的“开箱即用”。

我已经实现了一个覆盖onInterceptTouchEvent方法的GridView 。 我按照Fuzzical Logic的说明设置了OnTouchListener 。 我的问题是设置一个自定义的OnTouchListener,我的gridView的对象不能再点击。 那是因为GridView的默认OnTouchListener调用onItemClickListener?

我想有一个2方向可滚动的GridView,但仍然可以cliackable对象。 我是否应该实施自己的方法来检查触摸是否匹配项目,还是有更简单的方法来实现?

Grodak