Android'de dikey ve yatay kaydırma görünümü


152

Dikey ve yatay Scrollview için bir çözüm bulmaktan gerçekten yoruldum.

Bu özelliği uygulayan çerçevede herhangi bir görünüm / düzen olmadığını okudum, ama böyle bir şeye ihtiyacım var:

İçinde bir düzen tanımlamam gerekiyor, çocuk düzeni hareket için dikey / yatay kaydırma uygulamalıdır.

Başlangıçta düzen pikseli piksel hareket ettiren bir kod uygulandı, ancak bunun doğru yol olmadığını düşünüyorum. ScrollView ve Horizontal ScrollView ile denedim ama istediğim gibi hiçbir şey çalışmıyor, çünkü sadece dikey veya yatay kaydırma yapıyor.

Tuval benim çözümüm değil çünkü dinleyicileri birinin alt öğelerine eklemem gerekiyor.

Ne yapabilirim?



14
Bunun Android ile birlikte sunulmaması kesinlikle çok saçma. Yarım düzine başka kullanıcı arayüzü teknolojisiyle çalıştık ve yatay / dikey kaydırma kabı gibi temel bir şeye sahip olmamız duyulmamış.
flexicious.com

Tamam, son olarak datagrid için kendi yazdık: androidjetpack.com/Home/AndroidDataGrid . Yatay / dikey kaydırmadan çok daha fazlasını yapar. Ancak fikir temel olarak bir HScroller'ı Dikey Kaydırıcıya sarmaktır. Ayrıca, iç kaydırma çubuğunu ve diğer birkaç maskaralığı hedeflemek için çocuk yöntemlerini ekle / kaldır'ı geçersiz kılmanız gerekir, ancak işe yarar.
flexicious.com

Yanıtlar:


91

Yukarıdaki önerileri bir araya getirerek iyi bir çözüm elde edebildim:

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

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

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

}

tasarım:

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

Bu harika bir cevap, görünümde de değiştirilmesi gereken diğer kaydırma öğeleri vardı. Tüm yapmam gereken, diğerleriyle birlikte onların scrollby tetiklemek oldu.
T. Markle

1
Harika! Hızı hesaba katmak için birkaç ayar, ve bu mükemmel olurdu (ayrıca, LinearLayoutsanırım
ilkine

Hey Mehdi bana, hangi kontrol / widget üzerinde aktivite sınıfında dokunmatik dinleyiciyi yeniden kaydettiğinizi söyleyebilir misiniz?
Shachillies

@DeepakSharma gecikmesi için özür dileriz. Etkinliğe herhangi bir dokunma dinleyicisi kaydettirmedim, etkinliğin onTouchEvent'ini geçersiz kıldım.
Mehdi Hijazi

@MahdiHijazi u Yatay Kaydırma ve Dikey Kaydırma senin kod eklemek misiniz github.com/MikeOrtiz/TouchImageView başarıyla düğmesi tıklandığında görüntüyü yakınlaştırma bu ancak kaydırma görüntüye başarısız
Erum

43

Bu, Google'da "Android dikey + yatay ScrollView" için ilk arama sonucu gibi göründüğünden, bunu buraya eklemem gerektiğini düşündüm. Matt Clark, Android kaynağına göre özel bir görünüm oluşturdu ve mükemmel çalışıyor gibi görünüyor: Two Dimensional ScrollView

Bu sayfadaki sınıfın görünümün yatay genişliğini hesaplayan bir hataya sahip olduğuna dikkat edin. Manuel Hilty'nin yaptığı bir düzeltme yorumlarda:

Çözüm: 808 satırındaki ifadeyi aşağıdaki şekilde değiştirin:

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


Düzenleme: Bağlantı artık çalışmıyor, ancak blog yazısının eski bir sürümünün bağlantısı .


3
Teşekkürler, aradığım şey bu.
Andrey Agibalov

1
Bu benim için küçük bir değişiklikten sonra bir cazibe gibi çalışıyor. Ben yeniden fillViewportve onMeasureScrollView kaynağı (v2.1) tam olarak gibi. Ayrıca ilk iki kurucuyu: this( context, null );ve ile değiştirdim this(context, attrs, R.attr.scrollViewStyle);. Bununla birlikte setVerticalScrollBarEnabledve setHorizontalScrollBarEnabledkodunu kullanarak kaydırma çubuğunu kullanabilirim .
olivier_sdg

Benim için de harika çalışıyor! Çok teşekkür ederim!
Avio

ama kaydırma başparmak boyutu ve kaydırma konumu yatay modda alt dikey ve sağdan nasıl elde edilir
Ravi

10
Bağlantılı yayın kayboldu.
14'te loeschg

28

Daha iyi bir çözüm buldum.

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

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

Bu işe yarıyor !!!

Başka bir düzen veya kontrol yüklemek istiyorsanız, yapı aynıdır.


Sadece bunu denedim ve çok iyi çalışıyor! Kaydırma göstergeleri veya fırlatması yoktur, ancak bu daha düşük seviyeli bir yaklaşım olduğundan, bu şeyler oldukça kolay bir şekilde inşa edilebilir. Teşekkürler!
ubzack

Ağ üzerinden SSH uzaktan komutlarının sonucundan gerçek zamanlı çıktı veren iki boyutlu kaydırılabilir bir görünüm yazmak için de benim için iyi çalıştı.
pilcrowpipe

@Kronos: Yalnızca yatay kaydırma yapmak istersem ne olur? Y parametrem container.scrollBy'de (currentX - x2, currentY - y2) ne olmalıdır? Sadece yatay kaydırma yapabilmemizin bir yolu var mı?
Ashwin

@Kronos: Çok ileri kaydırıyor. Sona ulaşıldığında kaydırma işlemini durdurmanın bir yolu var mı?
Ashwin

Düğmeler kaydırılamaz, Neden?
salih kallai

25

Ben kullanıyorum ve iyi çalışıyor:

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

Kaynak bağlantı burada: Android-spa


2
En iyi ihtimalle statik içerikler için "gayet iyi" çalışır. Birden fazla Google mühendisi, kullanmaya çalıştığınız şeyin sorun yaşayacağını söyledi ( groups.google.com/group/android-developers/browse_frm/thread/… ve groups.google.com/group/android-beginners/browse_thread/thread/ … ).
CommonsWare

4
@CommonsWare: Birden fazla parlak Google mühendisine saygı gösterirken, size kendi bileşenlerinizi sıfırdan yeniden yazmanızı söyledikleri bu konu başlıklarında: bu en iyi yoldur. Elbette doğrudur. Ama bu çözümün kötü olduğunu söylemiyorlar ve işe yarıyorsa ... Belki onlar için bir dakika sürer, benim için mevcut bileşenleri kullanarak bazı xml yazmak daha iyidir. "Statik içerik" ne anlama geliyor? Düğme ve görüntüler kullanıyorum.
Redax

3
"Statik içerik" ile, dokunma olaylarının kendilerini içermeyen şeyleri kastediyorum. Demek istediğim, bu yanıtı okuyan diğerleri için, çözümünüz ImageViewkaydırılabilir içerik olarak tek bir çözüm için çalışabilirken, diğer içerikler için keyfi olabilir veya olmayabilir ve Google'ın yaklaşımınızla ilgili sorunlar olacağına inanıyor. Google'ın görüşü de gelecekteki gelişmeler açısından önemlidir - insanlara ilk etapta kullanmamalarını tavsiye ediyorsa, yaklaşımınızın uzun vadede çalıştığından emin olmayabilirler.
CommonsWare

Bu benim için iyi çalışıyor ... Bir iplik kullanarak bu kaydırma görünümünde bir imag ferahlatıcı
sonu thomas

19

Benim çözümüm Mehdi Hijazi cevabına dayalı , ancak herhangi bir özel görüş olmadan:

Yerleşim:

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

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

Kaydırma görüntülerinin sırasını değiştirebilirsiniz. Sadece düzen ve kod sırasını değiştirin. Ve açıkça WateverViewYouWant yerine her iki yönde kaydırmak istediğiniz düzeni / görünümleri koymak.


HScroll.setOnTouchListener içinde false döndürmenizi önemle tavsiye ederim. Yanlış olarak değiştirdiğimde, liste her iki yönde de parmağınızla "düzgün otomatik" olarak ilerlemeye başladı.
Greta Radisauskaite

1
Önce yatay olarak kaydırırken çalışır. Dikey ilk olduğunda, sadece dikey olarak gider
Irhala

6

Seçenek # 1: Eşzamanlı yatay ve dikey kaydırma gerektirmeyen yeni bir kullanıcı arayüzü tasarımı yapabilirsiniz.

Seçenek # 2: kaynak kodu edinebilirsiniz ScrollViewve HorizontalScrollViewçekirdek Android ekibi bu uygulamaya öğrenmek ve kendi yaratmak BiDirectionalScrollViewuygulaması.

Seçenek # 3: Widget sistemini kullanmanızı ve doğrudan Tuval'e çizim yapmanızı gerektiren bağımlılıklardan kurtulabilirsiniz.

Seçenek # 4: Aradığınızı uygulayan bir açık kaynak uygulamasına rastlarsanız, nasıl yaptıklarını görün.


6

Bunu dene

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

İki Boyutlu Scrollview bağlantısı öldüğünden onu alamadım, bu yüzden kendi bileşenimi oluşturdum. Fırlatmayı idare ediyor ve benim için düzgün çalışıyor. Tek kısıtlama, wrap_content öğesinin bu bileşen için düzgün çalışmayabileceğidir.

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


2

Senin sorunun için bir çözümüm var. Yalnızca dikey kaydırmayı işlediği ScrollView kodunu kontrol edebilir, yatay kodu yok sayar ve bunu değiştirebilirsiniz. Web görünümü gibi bir görünüm istedim, bu yüzden ScrollView değiştirildi ve benim için iyi çalıştı. Ancak bu ihtiyaçlarınızı karşılamayabilir.

Ne tür bir kullanıcı arayüzü hedeflediğinizi bildirin.

Saygılarımızla,

Ravi Pandit


1

Kod ile oynarken ScrollView içine bir HorizontalScrollView koyabilirsiniz. Böylece, aynı görünümde iki kaydırma yöntemine sahip olabilirsiniz.

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

Umarım bu size yardımcı olabilir.


1
Bu iyi bir çözüm değil. Dikkat ederseniz, görünümü sürüklerken her zaman dikey veya yatay sürüklersiniz. İç içe kaydırma görünümlerini kullanarak diyagonal boyunca sürükleyemezsiniz.
Sky Kelsey

Çapraz kaydırma eksikliğinden daha kötüsü, iç içe olduğu için her iki kaydırma çubuğunun da görünüm kenarında kalmamasıdır. Daha iyi bir ScrollView yanıttır ve Cachapa'nın Matt Clark'ın koduyla bağlantısı şu anda tamlık ve genelleme nedeniyle en iyi çözümdür.
Huperniketes

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.