我希望拥有一个线性布局,顶部有一个标题栏,下面是一个网页视图。标题栏很短,网页视图可能比屏幕更长和更宽。
如何最好地实现水平和垂直滚动?在HorizontalScrollView中嵌套一个ScrollView是否是一个好主意?
我希望拥有一个线性布局,顶部有一个标题栏,下面是一个网页视图。标题栏很短,网页视图可能比屏幕更长和更宽。
如何最好地实现水平和垂直滚动?在HorizontalScrollView中嵌套一个ScrollView是否是一个好主意?
还有一种方法。将修改过的HorizontalScrollView作为ScrollView的包装器。当捕获触摸事件时,正常的HorizontalScrollView不会将其转发到ScrollView,因此您只能单向滚动。这里是解决方案:
package your.package;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;
import android.view.MotionEvent;
import android.content.Context;
import android.util.AttributeSet;
public class WScrollView extends HorizontalScrollView
{
public ScrollView sv;
public WScrollView(Context context)
{
super(context);
}
public WScrollView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public WScrollView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
@Override public boolean onTouchEvent(MotionEvent event)
{
boolean ret = super.onTouchEvent(event);
ret = ret | sv.onTouchEvent(event);
return ret;
}
@Override public boolean onInterceptTouchEvent(MotionEvent event)
{
boolean ret = super.onInterceptTouchEvent(event);
ret = ret | sv.onInterceptTouchEvent(event);
return ret;
}
}
使用:
@Override public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
/*BIDIRECTIONAL SCROLLVIEW*/
ScrollView sv = new ScrollView(this);
WScrollView hsv = new WScrollView(this);
hsv.sv = sv;
/*END OF BIDIRECTIONAL SCROLLVIEW*/
RelativeLayout rl = new RelativeLayout(this);
rl.setBackgroundColor(0xFF0000FF);
sv.addView(rl, new LayoutParams(500, 500));
hsv.addView(sv, new LayoutParams(WRAP_CONTENT, MATCH_PARENT /*or FILL_PARENT if API < 8*/));
setContentView(hsv);
}
onTouchEvent
和onInterceptTouchEvent
方法,并将MotionEvent对象转发到两个滚动视图,就像这个答案中所描述的那样。流畅的体验,双向滚动。 - sulaiavailableToScroll
变量等于0。 - Android developer我花了很长时间搜索才使这个工作,并最终在这里找到了这个帖子。wasikuss的答案接近解决方案,但仍然不能正常工作。以下是它如何非常好地工作(至少对我来说(Android 2.3.7))。我希望它也适用于任何其他Android版本。
创建一个名为VScrollView的类:
package your.package.name;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;
public class VScrollView extends ScrollView {
public HorizontalScrollView sv;
public VScrollView(Context context) {
super(context);
}
public VScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
sv.dispatchTouchEvent(event);
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
super.onInterceptTouchEvent(event);
sv.onInterceptTouchEvent(event);
return true;
}
}
<your.package.name.VScrollView
android:id="@+id/scrollVertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<HorizontalScrollView
android:id="@+id/scrollHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TableLayout
android:id="@+id/table"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:stretchColumns="*" >
</TableLayout>
</HorizontalScrollView>
</your.package.name.VScrollView>
hScroll = (HorizontalScrollView) findViewById(R.id.scrollHorizontal);
vScroll = (VScrollView) findViewById(R.id.scrollVertical);
vScroll.sv = hScroll;
...这就是它的工作原理。至少对我来说是这样。
todo's
,但它确实足以同时水平和垂直滚动内容。以下是简单的解决方法: 在你的活动中获取外部scrollView的引用(我假设是垂直scrollView),以及该scrollView的第一个子项的引用。
Scrollview scrollY = (ScrollView)findViewById(R.id.scrollY);
LinearLayout scrollYChild = (LinearLayout)findViewById(R.id.scrollYChild);
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
scrollYChild.dispatchTouchEvent(event);
scrollY.onTouchEvent(event);
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event)
{
if (super.onInterceptTouchEvent(event) || vscroll.onInterceptTouchEventInt(event)) {
onTouchEvent(event);
return true;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
/* Beware: One ugliness of passing on events like this is that normally a ScrollView will
do transformation of the event coordinates which we're not doing here, mostly because
things work well enough without doing that.
For events that we pass through to the child view, transformation *will* happen (because
we're completely ignoring those and let the (H)ScrollView do the transformation for us).
*/
vscroll.onTouchEventInt(event);
return true;
}
这里的“vscroll”是从ScrollView继承而来的“InnerScroller”,在事件处理方面进行了一些更改:我做了一些可怕的事情,以确保直接来自Android的触摸事件被丢弃,并且它只会从外部类中接收它们 - 然后仅将其传递给超类:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
/* All touch events should come in via the outer horizontal scroller (using the Int
functions below). If Android tries to send them here directly, reject. */
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
/* It will still try to send them anyway if it can't find any interested child elements.
Reject it harder (but pretend that we took it). */
return true;
}
public boolean onInterceptTouchEventInt(MotionEvent event) {
return super.onInterceptTouchEvent(event);
}
public boolean onTouchEventInt(MotionEvent event) {
super.onTouchEvent(event);
}
HorizontalScrollView: Invalid pointerId=-1 in onTouchEvent
,以及不喜欢创建两个滚动视图的需求,因此作者进行了修改。下面是作者的类代码:public class ScrollView2D extends ScrollView {
private HorizontalScrollView innerScrollView;
public ScrollView2D(Context context) {
super(context);
addInnerScrollView(context);
}
public ScrollView2D(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() == 1) {
View subView = getChildAt(0);
removeViewAt(0);
addInnerScrollView(getContext());
this.innerScrollView.addView(subView);
} else {
addInnerScrollView(getContext());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean handled = super.onTouchEvent(event);
handled |= this.innerScrollView.dispatchTouchEvent(event);
return handled;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
super.onInterceptTouchEvent(event);
return true;
}
public void setContent(View content) {
if (content != null) {
this.innerScrollView.addView(content);
}
}
private void addInnerScrollView(Context context) {
this.innerScrollView = new HorizontalScrollView(context);
this.innerScrollView.setHorizontalScrollBarEnabled(false);
addView(this.innerScrollView);
}
}
setContent(View content)
,以便让此ScrollView2D
知道它的内容是什么。// Get or create a ScrollView2D.
ScrollView2D scrollView2D = new ScrollView2D(getContext());
scrollView2D.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
addView(scrollView2D);
// Set the content of scrollView2D.
RelativeLayout testView = new RelativeLayout(getContext());
testView.setBackgroundColor(0xff0000ff);
testView.setLayoutParams(new ViewGroup.LayoutParams(2000, 2000));
scrollView2D.setContent(testView);
我知道你已经接受了你的答案,但也许这可以给你一些想法。
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<HorizontalScrollView
android:layout_alignParentBottom="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:src="@drawable/device_wall"
android:scaleType="center"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</HorizontalScrollView>
</RelativeLayout>
</LinearLayout>
</ScrollView>
WebView
内部滚动,就像普通的Web浏览器一样。 - CommonsWare