Scrollview vertical et horizontal sur android

je suis vraiment fatigué à la recherche d'une solution pour le Scrollview vertical et horizontal.

j'ai lu qu'il n'y a pas de vues/layouts dans le cadre qui implémentent cette fonctionnalité, mais j'ai besoin de quelque chose comme ceci:

je dois définir un layout dans un autre, le layout enfant doit mettre en œuvre défilement vertical/horizontal pour se déplacer.

initialement mis en œuvre un code qui a déplacé la disposition pixel par pixel, mais je pense que n'est pas de la bonne façon. Je l'ai essayé avec ScrollView et ScrollView Horizontal mais rien ne fonctionne comme je le veux, parce qu'il ne met en œuvre que le défilement vertical ou horizontal.

Toile N'est pas ma solution parce que j'ai besoin d'attacher des écouteurs dans certains éléments enfants.

Que puis-je faire?

142
demandé sur Damien Sawyer 2010-01-11 23:44:04

10 réponses

mélangeant quelques-unes des suggestions ci-dessus, et a pu obtenir une bonne solution:

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

Custom HorizontalScrollView:

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

the Scrollbleimageactivity:

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

}

la mise en page:

<?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>
86
répondu Mahdi Hijazi 2011-07-16 09:55:55

comme cela semble être le premier résultat de recherche dans Google pour" Android vertical+ScrollView horizontal", j'ai pensé que je devrais ajouter ceci ici. Matt Clark a construit une vue personnalisée basée sur la source Android, et il semble fonctionner parfaitement: two Dimensional ScrollView

attention, la classe de cette page a un bug qui calcule la largeur horizontale de la vue. Une correction de Manuel Hilty est dans les commentaires:

Solution: remplacer l'énoncé à la ligne 808 par le suivant:

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



modifier: le lien ne fonctionne plus mais voici un lien vers une ancienne version du blogpost .

41
répondu Cachapa 2014-05-10 12:06:46

j'ai trouvé une meilleure solution.

XML: (de la conception.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>

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

ça marche!!!

si vous voulez charger d'autres dispositions ou de contrôle, la structure est la même.

28
répondu Kronos 2010-01-13 15:41:10

Je l'utilise et fonctionne très bien:

<?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>

le lien source est ici: Android-spa

25
répondu Redax 2011-06-04 09:06:31

Ma solution basée sur Mahdi Hijazi réponse , mais sans toutes les vues personnalisées:

Modèle:

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

Code (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;
        }
    });

vous pouvez changer l'ordre des scrollviews. Il suffit de changer leur ordre dans la mise en page et dans le code. Et évidemment au lieu de WateverViewYouWant vous mettez la mise en page/Vues que vous voulez faire défiler les deux directions.

16
répondu Yan.Yurkin 2017-05-23 12:18:02

Option # 1: vous pouvez proposer un nouveau design D'interface utilisateur qui ne nécessite pas de défilement horizontal et vertical simultané.

Option #2: Vous pouvez obtenir le code source de ScrollView et HorizontalScrollView , apprendre comment le noyau de L'équipe Android mis en œuvre ces, et de créer votre propre BiDirectionalScrollView mise en œuvre.

Option #3: vous pouvez vous débarrasser des dépendances qui vous obligent à utiliser le système de widget et dessiner directement sur la toile.

Option #4: Si vous tombez sur une application open source qui semble implémenter ce que vous recherchez, regardez comment ils l'ont fait.

6
répondu CommonsWare 2010-01-11 20:58:46

Essayez cette

<?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>
6
répondu MBMJ 2012-06-13 11:16:59

puisque le lien En deux dimensions de Scrollview est mort, je n'ai pas pu l'obtenir et j'ai donc créé mon propre composant. Il gère jetant et fonctionne correctement pour moi. La seule restriction est que wrap_content pourrait ne pas fonctionner correctement pour ce composant.

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

4
répondu androidseb 2014-03-31 21:11:05

j'ai une solution pour votre problème. Vous pouvez vérifier le code ScrollView il ne gère que le défilement vertical et ignore le défilement horizontal et le modifier. Je voulais une vue comme une webview, donc ScrollView modifié et il a bien fonctionné pour moi. Mais cela pourrait ne pas convenir à vos besoins.

dites-moi quel type D'UI vous ciblez.

Cordialement,

Ravi Pandit

2
répondu Ravi Pandit 2015-05-11 10:08:01

en jouant avec le code, vous pouvez mettre un ScrollView horizontal dans un ScrollView. Ainsi, vous pouvez avoir les deux de défilement dans la même vue.

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

j'espère que cela pourra vous aider.

1
répondu Eriatolc 2011-04-07 08:59:57