我真的很想为垂直和水平Scrollview解决方案。

我读到,在框架中没有实现此功能的任何视图/布局,但是我需要这样的东西:

我需要定义其他布局,子布局必须实现垂直/水平滚动才能移动。

最初实现了一个代码,可以逐像素移动布局,但是我认为这不是正确的方法。
我在ScrollView和Horizo​​ntal ScrollView上进行了尝试,但没有任何效果如我所愿,因为它仅实现垂直或水平滚动。

画布不是我的解决方案因为我需要将侦听器附加到某人的子元素中。

我该怎么办?

评论

stackoverflow.com/questions/11775677/…

这是非常荒谬的,Android无法立即使用。我们已经使用了六种其他UI技术,并且闻所未闻的没有水平/垂直滚动容器这样的基本内容。

好的,最后我们为datagrid编写了自己的文件:androidjetpack.com/Home/AndroidDataGrid。除了水平/垂直滚动外,还可以做更多的事情。但是这个想法基本上是将HScroller包装在Vertical Scroller中。您还必须重写add / remove子方法以将内部滚动条和其他一些恶作剧作为目标,但是它可以工作。

您可能会发现此答案很有用stackoverflow.com/a/62733625/311445

#1 楼

混合上面的一些建议,就能得到很好的解决方案:

自定义ScrollView:

package com.scrollable.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;

public class VScroll extends ScrollView {

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

    public VScroll(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public VScroll(Context context) {
        super(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return false;
    }
}


自定义Horizo​​ntalScrollView:

package com.scrollable.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;

public class HScroll extends HorizontalScrollView {

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

    public HScroll(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public HScroll(Context context) {
        super(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return false;
    }
}



package com.scrollable.view;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
import android.widget.ScrollView;

public class ScrollableImageActivity extends Activity {

    private float mx, my;
    private float curX, curY;

    private ScrollView vScroll;
    private HorizontalScrollView hScroll;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        vScroll = (ScrollView) findViewById(R.id.vScroll);
        hScroll = (HorizontalScrollView) findViewById(R.id.hScroll);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float curX, curY;

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                mx = event.getX();
                my = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                curX = event.getX();
                curY = event.getY();
                vScroll.scrollBy((int) (mx - curX), (int) (my - curY));
                hScroll.scrollBy((int) (mx - curX), (int) (my - curY));
                mx = curX;
                my = curY;
                break;
            case MotionEvent.ACTION_UP:
                curX = event.getX();
                curY = event.getY();
                vScroll.scrollBy((int) (mx - curX), (int) (my - curY));
                hScroll.scrollBy((int) (mx - curX), (int) (my - curY));
                break;
        }

        return true;
    }

}


布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <com.scrollable.view.VScroll android:layout_height="fill_parent"
        android:layout_width="fill_parent" android:id="@+id/vScroll">
        <com.scrollable.view.HScroll android:id="@+id/hScroll"
            android:layout_width="fill_parent" android:layout_height="fill_parent">
            <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/bg"></ImageView>
        </com.scrollable.view.HScroll>
    </com.scrollable.view.VScroll>

</LinearLayout>


评论


这是一个很好的答案,我在视图中还有其他滚动元素也需要更改。我要做的就是与其他人一起触发他们的滚动。

– T. Markle
2012年10月10日15:31

大!进行一些调整以考虑到速度,这将是完美的(而且,我猜您不需要初始的LinearLayout)

–罗默德·布鲁内特(Romuald Brunet)
2012年10月5日6:50



嗨,马赫迪(Mahdi),您能告诉我,您在活动课堂上重新注册了哪个控件/部件上的触摸监听器。

–沙皮狗
13年1月24日,9:50

抱歉@DeepakSharma的延迟。我没有在活动中注册任何触摸侦听器,只是重写了活动的onTouchEvent。

–马赫迪·希亚兹(Mahdi Hijazi)
13年2月18日在7:32

@MahdiHijazi您能在github.com/MikeOrtiz/TouchImageView中添加水平滚动和垂直滚动的代码吗,这是在单击按钮时成功缩放图像,但滚动图像失败

– Erum
2014年1月31日12:24

#2 楼

由于这似乎是Google中“ Android垂直+水平ScrollView”的第一个搜索结果,因此,我认为应该在此处添加此内容。马特·克拉克(Matt Clark)已基于Android源构建了一个自定义视图,它似乎运行良好:二维ScrollView

请注意,该页面中的类存在计算视图水平宽度的错误。注释中有Manuel Hilty的修复程序:


解决方案:将808行的语句替换为以下内容:

final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);



编辑:链接不再起作用,但这是旧版本博客的链接。

评论


谢谢,这就是我想要的。

–安德烈·阿吉巴洛夫(Andrey Agibalov)
2011-12-10 14:11

经过一些小的修改,对我来说,它就像是一种魅力。我完全像ScrollView源(v2.1)重新实现了fillViewport和onMeasure。我还更改了两个第一个构造函数:this(context,null);和this(context,attrs,R.attr.scrollViewStyle);。这样,我可以在代码中使用setVerticalScrollBarEnabled和setHorizo​​ntalScrollBarEnabled来使用滚动条。

–olivier_sdg
2012年5月11日7:42



对我来说也很棒!非常感谢你!

– Avio
2012年5月18日在17:19

但是如何在水平模式下从垂直底部和右侧获取滚动拇指大小和滚动位置

–拉维
13年5月6日在4:42

看起来该linkedin帖子已经消失了。

– loesch
2014年3月24日22:10

#3 楼

我找到了更好的解决方案。

XML:(design.xml)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
  <FrameLayout android:layout_width="90px" android:layout_height="90px">
    <RelativeLayout android:id="@+id/container" android:layout_width="fill_parent" android:layout_height="fill_parent">        
    </RelativeLayout>
</FrameLayout>
</FrameLayout>


Java代码:

public class Example extends Activity {
  private RelativeLayout container;
  private int currentX;
  private int currentY;

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.design);

    container = (RelativeLayout)findViewById(R.id.container);

    int top = 0;
    int left = 0;

    ImageView image1 = ...
    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    layoutParams.setMargins(left, top, 0, 0);               
    container.addView(image1, layoutParams);

    ImageView image2 = ...
    left+= 100;
    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    layoutParams.setMargins(left, top, 0, 0);               
    container.addView(image2, layoutParams);

    ImageView image3 = ...
    left= 0;
    top+= 100;
    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    layoutParams.setMargins(left, top, 0, 0);               
    container.addView(image3, layoutParams);

    ImageView image4 = ...
    left+= 100;     
    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    layoutParams.setMargins(left, top, 0, 0);               
    container.addView(image4, layoutParams);
  }     

  @Override 
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            currentX = (int) event.getRawX();
            currentY = (int) event.getRawY();
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            int x2 = (int) event.getRawX();
            int y2 = (int) event.getRawY();
            container.scrollBy(currentX - x2 , currentY - y2);
            currentX = x2;
            currentY = y2;
            break;
        }   
        case MotionEvent.ACTION_UP: {
            break;
        }
    }
      return true; 
  }
}


这是可行的!

如果要加载其他布局或控件,其结构是相同的。

评论


刚刚尝试过,效果很好!它没有滚动指示器,也没有猛冲,但是因为这是一个较低级别的方法,所以可以很容易地在此基础上构建这些东西。谢谢!

– ubzack
2011年12月3日,21:35

对我来说,编写一个二维可滚动视图也很有效,该视图可通过网络通过SSH远程命令的结果输出实时输出。

–茅草管
2012年7月27日在22:17

@Kronos:如果我只想水平滚动怎么办?我的y参数应该在container.scrollBy(currentX-x2,currentY-y2)中。有什么方法可以使它仅水平滚动?

–阿什温
2012年9月21日在12:19

@Kronos:滚动太远。到达终点时,有什么方法可以停止滚动吗?

–阿什温
2012年9月21日15:56

按钮不可滚动,为什么?

–萨利赫·卡莱
17 Mar 8 '17 at 20:24

#4 楼

我使用它并能正常工作:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:id="@+id/ScrollView02" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content"
            xmlns:android="http://schemas.android.com/apk/res/android">
<HorizontalScrollView android:id="@+id/HorizontalScrollView01" 
                      android:layout_width="wrap_content" 
                      android:layout_height="wrap_content">
<ImageView android:id="@+id/ImageView01"
           android:src="@drawable/pic" 
           android:isScrollContainer="true" 
           android:layout_height="fill_parent" 
           android:layout_width="fill_parent" 
           android:adjustViewBounds="true">
</ImageView>
</HorizontalScrollView>
</ScrollView>


源链接在这里:Android-spa

评论


最多只能对静态内容“很好”地工作。多个Google工程师说过,您尝试使用的内容会出现问题(groups.google.com/group/android-developers/browse_frm/thread/…和groups.google.com/group/android-beginners/browse_thread/thread/ …)。

– CommonsWare
2011年6月4日13:03

@CommonsWare:尊重杰出的Google多位工程师,他们在这些线程中告诉您从头开始重写自己的组件:这是最好的方法。当然是真的。但是他们并没有说这个解决方案不好,如果可行的话……也许对他们来说要花一点时间,对我而言,最好使用现有组件来编写一些xml。 “静态内容”是什么意思?我使用按钮和图像。

– Redax
2011年6月4日下午16:47

“静态内容”是指本身不涉及触摸事件的事物。我的观点是-对于其他阅读此答案的人-是虽然您的解决方案可能适用于单个ImageView作为可滚动内容,但它可能适用于或可能不适用于任意其他内容,并且Google认为您的方法会存在问题。 Google的意见对于未来的发展也很重要-如果他们建议人们不要首先使用它,他们可能不会试图确保您的方法长期有效。

– CommonsWare
2011年6月4日17:37

这对我来说很好用...我正在使用线程刷新此滚动视图中的图像视图

– Sonu托马斯
2012年1月5日在6:02

#5 楼

我的解决方案基于Mahdi Hijazi答案,但没有任何自定义视图:

布局:

<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/scrollHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ScrollView 
        android:id="@+id/scrollVertical"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" >

        <WateverViewYouWant/>

    </ScrollView>
</HorizontalScrollView>


代码(onCreate / onCreateView):

    final HorizontalScrollView hScroll = (HorizontalScrollView) value.findViewById(R.id.scrollHorizontal);
    final ScrollView vScroll = (ScrollView) value.findViewById(R.id.scrollVertical);
    vScroll.setOnTouchListener(new View.OnTouchListener() { //inner scroll listener         
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return false;
        }
    });
    hScroll.setOnTouchListener(new View.OnTouchListener() { //outer scroll listener         
        private float mx, my, curX, curY;
        private boolean started = false;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            curX = event.getX();
            curY = event.getY();
            int dx = (int) (mx - curX);
            int dy = (int) (my - curY);
            switch (event.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    if (started) {
                        vScroll.scrollBy(0, dy);
                        hScroll.scrollBy(dx, 0);
                    } else {
                        started = true;
                    }
                    mx = curX;
                    my = curY;
                    break;
                case MotionEvent.ACTION_UP: 
                    vScroll.scrollBy(0, dy);
                    hScroll.scrollBy(dx, 0);
                    started = false;
                    break;
            }
            return true;
        }
    });


您可以更改滚动视图的顺序。只需在布局和代码中更改其顺序即可。显然,您要放置两个方向的布局/视图而不是WateverViewYouWant。

评论


我强烈建议在hScroll.setOnTouchListener中返回false。当我更改为false时,列表开始在两个方向上沿手指向上“平滑自动”滚动。

– Greta Radisauskaite
14-10-29在14:24

首先水平滚动时有效。首先是垂直时,仅垂直

–艾哈拉
17年7月4日在12:31

#6 楼

选项1:您可以提出一种不需要同时进行水平和垂直滚动的新UI设计。

选项2:您可以获取ScrollViewHorizontalScrollView的源代码,了解其核心Android团队实现了这些功能,并创建了自己的BiDirectionalScrollView实现。

方法#3:您可以摆脱需要使用小部件系统并直接绘制到Canvas的依赖项。

方法#4:如果偶然发现了似乎可以实现您所寻找目标的开源应用程序,请查看它们是如何实现的。

#7 楼

试试这个

<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:id="@+id/Sview" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        xmlns:android="http://schemas.android.com/apk/res/android">
<HorizontalScrollView 
   android:id="@+id/hview" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content">
<ImageView .......
 [here xml code for image]
</ImageView>
</HorizontalScrollView>
</ScrollView>


#8 楼

由于“二维滚动视图”链接已失效,因此我无法获取它,因此我创建了自己的组件。它可以处理并为我正常工作。
唯一的限制是wrap_content可能不适用于该组件。

https://gist.github.com/androidseb/9902093

#9 楼

我有解决您问题的方法。您可以检查ScrollView代码,它仅处理垂直滚动,而忽略水平滚动并进行修改。我想要一个像webview的视图,因此对ScrollView进行了修改,对我来说效果很好。但这可能无法满足您的需求。

让我知道您要针对的UI。

关于,

Ravi Pandit

#10 楼

玩代码,您可以将Horizo​​ntalScrollView放入ScrollView。因此,您可以在同一视图中使用两种滚动方法。

来源:http://androiddevblog.blogspot.com/2009/12/creating-two-dimensions-scroll-view.html

我希望这可以为您提供帮助。

评论


这不是一个好的解决方案。如果您注意到,在拖动视图时,您总是在垂直或水平拖动。您无法使用嵌套滚动视图沿对角线拖动。

– Sky Kelsey
2012年2月25日在0:09

与缺少对角滚动相比,更糟糕的是缺少两个滚动条,因为它们是嵌套的,因此两个滚动条都保留在视图边缘。更好的ScrollView是答案,而由于完整性和通用性,此时Cachapa到Matt Clark代码的链接是最佳解决方案。

– Huperniketes
2012年6月3日15:32

#11 楼

使用这种方式
我尝试过修复它

将所有XML布局放入内部

<android.support.v4.widget.NestedScrollView 


我在此链接中对此进行了解释
垂直recyclerView和水平recyclerview一起滚动