Scrollview在android中纵向和横向

Kro*_*nos 146 android scrollview

我真的很想找到垂直和水平Scrollview的解决方案.

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

我需要在其他内部定义布局,子布局必须实现滚动垂直/水平移动.

最初实现了一个逐像素移动布局的代码,但我认为这不是正确的方法.我尝试使用ScrollView和Horizo​​ntal ScrollView,但没有任何工作像我想要的那样,因为它只实现垂直或水平滚动.

Canvas不是我的解决方案,因为我需要在某些子元素中附加侦听器.

我能做什么?

Mah*_*azi 89

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

自定义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;
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义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;
    }
}
Run Code Online (Sandbox Code Playgroud)

ScrollableImageActivity:

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

布局:

<?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>
Run Code Online (Sandbox Code Playgroud)


Cac*_*apa 42

由于这似乎是Google在"Android纵向+横向ScrollView"中的第一个搜索结果,我想我应该在这里添加它.Matt Clark已经构建了一个基于Android源的自定义视图,它看起来效果很好:Two Dimensional ScrollView

请注意,该页面中的类有一个计算视图水平宽度的错误.Manuel Hilty的修正案在评论中:

解决方案:使用以下内容替换第808行的语句:

final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);
Run Code Online (Sandbox Code Playgroud)


编辑:链接不再起作用,但这里是旧版博客文章的链接.

  • 看起来链接的帖子已经消失了. (9认同)
  • 大!我想知道为什么这不是Android的一部分? (6认同)
  • 谢谢,这就是我在寻找的东西. (3认同)

Kro*_*nos 28

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

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>
Run Code Online (Sandbox Code Playgroud)

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; 
  }
}
Run Code Online (Sandbox Code Playgroud)

这是有效的!

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


Red*_*dax 25

我用它并且工作正常:

<?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>
Run Code Online (Sandbox Code Playgroud)

源链接在这里:Android-spa

  • @CommonsWare:惠特尊敬的多位Google工程师,在那些线程中他们告诉你从头开始重写自己的组件:这是最好的方法.当然是真的.但他们并没有说这个解决方案是坏的,如果它有效......也许对他们来说需要一分钟,对我来说最好用现有的组件编写一些xml.什么是"静态内容"?我使用按钮和图像. (3认同)
  • "静态内容"是指不涉及触摸事件本身的事物.我的观点 - 对于其他读这个答案的人 - 是,虽然你的解决方案可能适用于单个`ImageView`作为可滚动内容,但它可能适用于或可能不适用于任意其他内容,并且Google认为会出现问题你的方法.谷歌的意见对于未来的发展也很重要 - 他们可能不会试图确保你的方法长期运作,如果他们建议人们不要首先使用它. (3认同)
  • 它对静态内容起到"好的"作用.多位Google工程师表示,您尝试使用的内容会出现问题(http://groups.google.com/group/android-developers/browse_frm/thread/c50acbe68ec98174/7d234358e2a57775和http://groups.google.com/组/ Android的初学者/ browse_thread /线程/ c05925aca7479d18). (2认同)

Yan*_*kin 18

我的解决方案基于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>
Run Code Online (Sandbox Code Playgroud)

代码(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;
        }
    });
Run Code Online (Sandbox Code Playgroud)

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


Com*_*are 6

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

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

选项#3:您可以摆脱要求您使用窗口小部件系统并直接绘制到Canvas的依赖项.

选项#4:如果您偶然发现一个似乎实现您所寻求的开源应用程序,请查看它们是如何实现的.


MBM*_*BMJ 6

试试这个

<?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>
Run Code Online (Sandbox Code Playgroud)


and*_*seb 6

因为Two Dimensional Scrollview链接已经死了所以我无法得到它所以我创建了自己的组件.它处理投掷并适合我.唯一的限制是wrap_content可能无法正常运行该组件.

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