ScrollView kaydırma konumlarını senkronize etme - Android


96

Android düzenimde 2 ScrollView var. Kaydırma konumlarını nasıl senkronize edebilirim?

Yanıtlar:


290

ScrollView'da bir yöntem var ...

protected void onScrollChanged(int x, int y, int oldx, int oldy)

Ne yazık ki Google, ona erişmemiz gerekeceğini hiç düşünmedi, bu yüzden korumalı yaptılar ve bir "setOnScrollChangedListener" kancası eklemediler. Yani bunu kendimiz için yapmak zorunda kalacağız.

Önce bir arayüze ihtiyacımız var.

package com.test;

public interface ScrollViewListener {

    void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);

}

Sonra ScrollViewListener kancasını sağlamak için ScrollView sınıfını geçersiz kılmamız gerekir.

package com.test;

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

public class ObservableScrollView extends ScrollView {

    private ScrollViewListener scrollViewListener = null;

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

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

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

    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }

    @Override
    protected void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if(scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }

}

Ve mevcut ScrollView etiketleri yerine bu yeni ObservableScrollView sınıfını mizanpajda belirtmeliyiz.

<com.test.ObservableScrollView
    android:id="@+id/scrollview1"
    ... >

    ...

</com.test.ObservableScrollView>

Son olarak, hepsini Layout sınıfında bir araya getirdik.

package com.test;

import android.app.Activity;
import android.os.Bundle;

public class Q3948934 extends Activity implements ScrollViewListener {

    private ObservableScrollView scrollView1 = null;
    private ObservableScrollView scrollView2 = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.q3948934);

        scrollView1 = (ObservableScrollView) findViewById(R.id.scrollview1);
        scrollView1.setScrollViewListener(this);
        scrollView2 = (ObservableScrollView) findViewById(R.id.scrollview2);
        scrollView2.setScrollViewListener(this);
    }

    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
        if(scrollView == scrollView1) {
            scrollView2.scrollTo(x, y);
        } else if(scrollView == scrollView2) {
            scrollView1.scrollTo(x, y);
        }
    }

}

ScrollTo () kodu, bizim için herhangi bir döngü koşulunun üstesinden gelir, bu nedenle bunun için endişelenmemize gerek yoktur. Tek uyarı, bu çözümün Android'in gelecekteki sürümlerinde çalışacağının garanti edilmemesidir, çünkü korumalı bir yöntemi geçersiz kılıyoruz.


Merhaba Andy Bu cevabı vermek için zaman ayırdığınız için teşekkürler - beni ileriye taşıdı. Tekrar teşekkürler. Tim
Tim

-Andy ben de kodu kullanıyorum ama bu bana boş bir işaretçi veriyor, bana yardım edebilir misin
hemant

@hemant NullPointer'ın hangi satıra atıldığını ve hangi Android sürümü ile çalıştığınızı belirtir misiniz?
sulai

Günün kahramanı: Hayatımı kurtardı! = D
Pedrão

Merhaba Andy, kod için teşekkürler. Harika çalışıyor. Bir şeyi bilmek isterim [sizde veya herhangi birinde1 ans varsa. buna] - scrollView'umu salladığımda, onscrollchanged yöntemi, kaydırma görünümü hareket ederken tüm X ve Y koordinatlarını kaydetmiyor. Bana sadece başlangıç ​​pozisyonunu ve son pozisyonu veriyor. Örneğin, Y = 10'dan fırlatmaya başlıyorum ve Y = 30'da bırakıyorum ve sonra fırlatma hızı onu Y = 50'ye götürüyor ve sonra duruyor. Yani onscroll sadece kayıtları değiştirdi - belki 10, 11, 12..30 ve sonra 49, 50. Tüm ara konumları da kaydettirip 10'dan 50'ye kadar tüm koordinatları nasıl alabilirim ??
alchemist

12

Andy'nin çözümünde bir gelişme: Kodunda, scrollTo kullanıyor, sorun şu ki, bir kaydırma görünümünü bir yöne çevirirseniz ve sonra başka bir yöne başka bir yöne fırlatırsanız, ilkinin önceki atışını durdurmadığını fark edeceksiniz hareket.

Bunun nedeni, scrollView'in hızlı hareketleri yapmak için computeScroll () kullanması ve scrollTo ile çakışmaya girmesidir.

Bunu önlemek için, onScrollChanged'yi şu şekilde programlayın:

    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
    if(interceptScroll){
        interceptScroll=false;
        if(scrollView == scrollView1) {
            scrollView2.onOverScrolled(x,y,true,true);
        } else if(scrollView == scrollView2) {
            scrollView1.onOverScrolled(x,y,true,true);
        }
        interceptScroll=true;
    }
}

ile interceptScroll true olarak başlatılmış statik bir boolean. (bu, ScrollChanged'da sonsuz döngülerden kaçınmaya yardımcı olur)

onOverScrolled, scrollView'un fırlamasını durdurmak için kullanılabileceğini bulduğum tek işlevdir (ancak kaçırdığım başkaları da olabilir!)

Bu işleve (korumalı) erişmek için, bunu ObservableScrollViewer'a eklemeniz gerekir.

public void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
    super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}

2
Ne güzel yakalandı evlat!
FranciscoBouza

5

Neden OnTouchListenerfaaliyetinizde sadece uygulamıyorsunuz ? Ardından onTouch yöntemini geçersiz kılın, ardından ilkinin kaydırma konumunu alın ScrollViewOne.getScrollY()ve güncelleyinScrollViewTwo.scrollTo(0, ScrollViewOne.getScrollY());

Sadece başka bir fikir ... :)


7
Bu işe yarayabilir, ancak dokunduğunuzda ve bıraktığınızda kaydırma görünümü yakalanmayan bıraktıktan sonra biraz daha kaydırılabilir.
richy

Java'da bu durumda scrollView ScrollViewOne referansını nasıl referans alabilirim / alabilirim?
Bunny Rabbit

Kaydırmanın başka yolları da vardır (örneğin onTrackballEvent ())
surfealokesea

Bu çok iyi bir fikirdir, ancak kaydırma konumunu alıp ayarlamak yerine, dokunma olayını ikinci kaydırma görünümüne göndermek daha kolaydır. Bu aynı zamanda ikinci kaydırma görünümünde "fırlatmanın" devam etmesini sağlayacaktır. MotionEvent newEvent = MotionEvent.obtain (olay); documentScrollView.dispatchTouchEvent (newEvent);
Eduard Mossinkoff

3

Android destek-v4 paketinde Android NestedScrollView,.

<ScrollView>düğümü <android.support.v4.widget.NestedScrollView>in layout xml ile değiştirebiliriz NestedScrollView.OnScrollChangeListenerve kaydırmayı işlemek için Java'da uygularız .

Bu işleri kolaylaştırır.

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.