webentwicklung-frage-antwort-db.com.de

Scrollview vertikal und horizontal in Android

Ich bin wirklich müde auf der Suche nach einer Lösung für den vertikalen und horizontalen Bildlauf.

Ich habe gelesen, dass es im Framework keine Ansichten/Layouts gibt, die diese Funktion implementieren, aber ich brauche Folgendes:

Ich muss ein Layout in einem anderen Element definieren. Das untergeordnete Layout muss vertikales/horizontales Scrollen zum Verschieben implementieren.

Zunächst wurde ein Code implementiert, der das Layout Pixel für Pixel verschoben hat, aber ich denke, das ist nicht der richtige Weg ... Ich habe es mit ScrollView und Horizontal ScrollView ausprobiert, aber nichts funktioniert so, wie ich es will, da es nur vertikales oder horizontales Scrollen implementiert .

Canvas ist nicht meine Lösung, weil ich Listener in untergeordneten Elementen von jemandem befestigen muss.

Was kann ich machen?

144
Kronos

Einige der oben genannten Vorschläge wurden gemischt und eine gute Lösung gefunden:

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

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

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

}

das Layout:

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

Da dies das erste Suchergebnis in Google für "Android vertical + horizontal ScrollView" zu sein scheint, dachte ich, ich sollte dies hier hinzufügen. Matt Clark hat eine benutzerdefinierte Ansicht basierend auf der Android-Quelle erstellt, und es scheint perfekt zu funktionieren: Two Dimensional ScrollView

Beachten Sie, dass die Klasse auf dieser Seite einen Fehler aufweist, der die horizontale Breite der Ansicht berechnet. Ein Fix von Manuel Hilty ist in den Kommentaren:

Lösung: Ersetzen Sie die Anweisung in Zeile 808 durch Folgendes:

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


Edit: Der Link funktioniert nicht mehr, aber hier ist ein Link zu einer alten Version des Blogposts .

41
Cachapa

Ich habe eine bessere Lösung gefunden.

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

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

Das funktioniert !!!

Wenn Sie ein anderes Layout oder eine andere Steuerung laden möchten, ist die Struktur gleich.

28
Kronos

Ich benutze es und funktioniert gut:

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

Der Quelllink ist hier: Android-Spa

25
Redax

Meine Lösung basiert auf Mahdi Hijazi answer , jedoch ohne benutzerdefinierte Ansichten:

Layout:

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

Sie können die Reihenfolge der Bildlaufansichten ändern. Ändern Sie einfach die Reihenfolge im Layout und im Code. Natürlich legen Sie anstelle von WateverViewYouWant das Layout/die Ansichten fest, in die Sie in beide Richtungen blättern möchten.

16
Yan.Yurkin

Versuche dies

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

Option 1: Sie können mit einem neuen UI-Design aufwarten, das kein gleichzeitiges horizontales und vertikales Scrollen erfordert.

Option 2: Sie können den Quellcode für ScrollView und HorizontalScrollView erhalten, erfahren, wie das Android-Kernteam diese implementiert hat, und eine eigene BiDirectionalScrollView-Implementierung erstellen.

Option 3: Sie können die Abhängigkeiten loswerden, bei denen Sie das Widget-System verwenden und direkt in den Canvas-Bereich zeichnen müssen.

Option 4: Wenn Sie auf eine Open-Source-Anwendung stoßen, die das zu implementieren scheint, wonach Sie suchen, schauen Sie nach, wie sie es getan haben.

6
CommonsWare

da der zweidimensionale Scrollview-Link nicht mehr verfügbar ist, konnte ich ihn nicht abrufen. Daher habe ich eine eigene Komponente erstellt. Es behandelt das Flinging und funktioniert für mich einwandfrei .. Die einzige Einschränkung besteht darin, dass wrap_content für diese Komponente möglicherweise nicht ordnungsgemäß funktioniert.

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

5
androidseb

Ich habe eine Lösung für dein Problem. Sie können den ScrollView-Code, der nur vertikales Scrollen behandelt, überprüfen und den horizontalen ignorieren und diesen ändern. Ich wollte eine Ansicht wie eine Webansicht, also modifizierte ScrollView und es funktionierte gut für mich. Dies kann jedoch nicht Ihren Bedürfnissen entsprechen.

Lassen Sie mich wissen, auf welche Art von Benutzeroberfläche Sie abzielen.

Grüße,

Ravi Pandit

2
Ravi Pandit

Wenn Sie mit dem Code spielen, können Sie eine HorizontalScrollView in eine ScrollView einfügen. Dadurch können Sie die zwei Scroll-Methode in derselben Ansicht anzeigen.

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

Ich hoffe das kann dir helfen.

1
Eriatolc

verwenden Sie diesen Weg Ich habe dies versucht. Ich habe es behoben

Setzen Sie Ihr gesamtes XML-Layout ein

<Android.support.v4.widget.NestedScrollView 

Das habe ich in diesem Link erklärt vertical recyclerView und Horizontal recyclerview scrolling together

0
Sirwan Rahimi