Non consentire lo scorrimento orizzontale durante lo scorrimento verticale (e viceversa)


17

Ho un elenco, con overflow-xe overflow-yimpostato su auto. Inoltre, ho impostato lo scorrimento del momento, quindi lo scorrimento del tocco funziona bene nei dispositivi mobili, usando webkit-overflow-scrolling: true.

Il problema, tuttavia, è che non riesco a capire come disabilitare lo scorrimento orizzontale quando si scorre verticalmente. Porta a un'esperienza utente davvero negativa, poiché lo scorrimento in alto a sinistra o in alto a destra farà scorrere diagonalmente la tabella. Quando l'utente scorre in verticale, NON voglio assolutamente scorrere in orizzontale fino a quando l'utente non smette di scorrere in verticale.

Ho provato quanto segue:

JS:

offsetX: number;
offsetY: number;
isScrollingHorizontally = false;
isScrollingVertically = false;

//Detect the scrolling events
ngOnInit() {
    this.scrollListener = this.renderer.listen(
      this.taskRows.nativeElement,
      'scroll',
      evt => {
        this.didScroll();
      }
    );

    fromEvent(this.taskRows.nativeElement, 'scroll')
      .pipe(
        debounceTime(100),
        takeUntil(this.destroy$)
      )
      .subscribe(() => {
        this.endScroll();
    });
}

didScroll() {
    if ((this.taskRows.nativeElement.scrollLeft != this.offsetX) && (!this.isScrollingHorizontally)){
        console.log("Scrolling horizontally")
        this.isScrollingHorizontally = true;
        this.isScrollingVertically = false;
        this.changeDetectorRef.markForCheck();
    }else if ((this.taskRows.nativeElement.scrollTop != this.offsetY) && (!this.isScrollingVertically)) {
        console.log("Scrolling Vertically")
        this.isScrollingHorizontally = false;
        this.isScrollingVertically = true;
        this.changeDetectorRef.markForCheck();
    }
}

endScroll() {
    console.log("Ended scroll")
    this.isScrollingVertically = false;
    this.isScrollingHorizontally = false;
    this.changeDetectorRef.markForCheck();
}

HTML:

<div
    class="cu-dashboard-table__scroll"
    [class.cu-dashboard-table__scroll_disable-x]="isScrollingVertically"
    [class.cu-dashboard-table__scroll_disable-y]="isScrollingHorizontally"
>

CSS:

&__scroll {
  display: flex;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overflow-x: auto;
  will-change: transform;
  -webkit-overflow-scrolling: touch;

  &_disable-x {
     overflow-x: hidden;
  }

  &_disable-y {
    overflow-y: hidden;
  }
}

Ma l'ho impostato ogni volta overflow-xo overflow-yper hiddenquando il suo stato fatto scorrere, lo scorrimento sarà tentennamenti e saltare di nuovo verso l'alto. Ho anche notato che questo webkit-overflow-scrolling: trueè il motivo per cui questo si verifica, quando lo rimuovo, il comportamento sembra arrestarsi, ma ne ho assolutamente bisogno per lo scorrimento del momento nei dispositivi mobili.

Come disabilitare lo scorrimento orizzontale quando si scorre verticalmente?


Non so come risolvere il problema di scorrimento. Forse fai un passo indietro e cerca di impedire lo scorrimento di uno dei due assi? Fuori tema: le tabelle non sono pensate per schermi veramente piccoli.
Joep Kockelkorn,

Manca una parentesi graffa nel tuo codice. Se lo aggiungi come snippet, vedrai un messaggio di errore nella console.
Razvan Zamfir,

solo un'idea stupida. perché non usare due cursori o cursori personalizzati per scorrere?
Thomas Ludewig,

Risposte:


4

Prova questo

HTML
<div
  class="cu-dashboard-table__scroll-vertical"
>
  <div
    class="cu-dashboard-table__scroll-horizontal"
  >
    <!-- Scroll content here -->
  </div>
</div>


CSS
&__scroll {
  &-horizontal {
    overflow-x: auto;
    width: 100%;
    -webkit-overflow-scrolling: touch;
  }

  &-vertical {
    overflow-y: auto;
    height: 100%;
    -webkit-overflow-scrolling: touch;
  }
}

Invece di usare un div per lo scorrimento, perché non ne usi due? Ne hai uno per X e uno per Y


1
Grande idea! non ci provo.
Josh O'Connor,

1
Lol, devo dire che è un'idea geniale.
frodo2975,

15

In genere è una cattiva pratica per il tuo design avere bisogno dello scorrimento multiassiale su dispositivi mobili, a meno che tu non stia mostrando grandi tabelle di dati. Detto questo, perché vuoi prevenirlo? Se un utente vuole scorrere in diagonale, per me non sembra la fine del mondo. Alcuni browser, come Chrome su OSX, fanno già quello che stai descrivendo per impostazione predefinita.

Se è necessario uno scorrimento su un asse, una possibile soluzione potrebbe essere quella di tenere traccia della posizione di scorrimento touchstarte degli touchmoveeventi. Se imposti una soglia di trascinamento inferiore a quella del browser, potresti essere in grado di fare le tue cose CSS prima che inizi a scorrere, evitando il glitch percepito. Inoltre, anche se continua a presentare anomalie, hai l'inizio del tocco e la posizione corrente del tocco. Da questi, se si registra la posizione di scorrimento iniziale del div, è possibile scorrere manualmente il div nella posizione corretta per contrastarlo saltando verso l'alto, se necessario. Un possibile algoritmo potrebbe apparire così:

// Touchstart handler
if (scrollState === ScrollState.Default) {
    // Record position and id of touch
    touchStart = touch.location
    touchStartId = touch.id.
    scrollState = ScrollState.Touching

    // If you have to manually scroll the div, first store its starting scroll position:
    containerTop = $('.myContainer').scrollTop();
    containerLeft = $('.myContainer').scrollLeft();
}

// Touchmove handler - If the user has dragged beyond a distance threshold,
// do the css classes swap.
if (touch.id === touchStartId && distance(touchStart, touch.location > threshold) {
    scrollState = ScrollState.Scrolling;
    swapCssClasses();

    // If you have to manually scroll the div to prevent jump:
    $('.myContainer').scrollTop(containerTop + (touch.location.y - touchStart.y));
    // Do the same for horizontal scroll.
}

// Then, listen for debounced scroll events, like you're already doing,
// to reset your state back to default.

Seconda idea: nel tuo gestore di scorrimento, invece di cambiare le classi css, imposta la posizione di scorrimento del div direttamente per l'asse che vuoi bloccare. Ad esempio, se si scorre in orizzontale, impostare sempre scrollTop sul valore iniziale. Questo potrebbe anche annullare lo scorrimento, non sono sicuro. Dovresti provarlo per vedere se funziona.


Ho provato questo, ma è stato super nervoso e la performance è stata orribile.
Josh O'Connor,

3

Esistono numerosi modi per provare a risolverlo. Alcune buone idee sono offerte qui.

Tuttavia, come altri hanno accennato, fare affidamento (o cercare di evitare) lo scorrimento multidimensionale è un cattivo odore UX - indicativo del fatto che UX è un problema. Non penso che questo sia un problema di sviluppo legittimo. Sarebbe meglio fare un passo indietro e rivalutare ciò che stai cercando di realizzare. Uno dei problemi potrebbe essere che, nel tentativo di rendere l'interfaccia utente più utilizzabile, confonderai gli utenti. L'usabilità descritta qui probabilmente causerebbe confusione.

Perché non riesco a scorrere in orizzontale?

Perché quando smetto di scorrere in verticale, solo allora posso scorrere in orizzontale?

Queste sono alcune domande che possono essere poste (non udibili).

Se stai cercando di consentire la visualizzazione di ulteriori informazioni dell'elenco di dati verticali solo quando l'utente ha selezionato la riga, sarebbe molto meglio avere semplicemente un elenco piatto per impostazione predefinita solo scorrevole verticalmente e attivare solo la verticale informazioni quando la "riga" è stata selezionata / attivata. La compressione dei dettagli ti riporta all'elenco verticale piatto.

Se devi saltare attraverso i cerchi per risolvere una sfida tecnica così marginale, è una buona indicazione che l'esperienza utente non è stata progettata per cominciare.


3

È necessario utilizzare tre contenitori.
Nel primo contenitore abilito lo scorrimento verticale e non autorizzo orizzontale.
Nel secondo, viceversa, abilito lo scorrimento orizzontale e non autorizzo verticale. Assicurarsi di utilizzare overflow-x: hidden;e overflow-y: hidden;, altrimenti i contenitori secondari potrebbero andare oltre il contenitore corrente.
Anche bisogno di usare min-width: 100%; min-height: 100%;.
Per il terzo contenitore dobbiamo usaredisplay: inline-block; e quindi il contenuto interno si estenderà a questo contenitore e le barre di scorrimento corrispondenti appariranno sui due blocchi principali.

HTML

<div class="scroll-y">
  <div class="scroll-x">
    <div class="content-container">

      <!-- scrollable content here -->

    </div>
  </div>
</div>

CSS

.scroll-y {
  position: absolute;
  overflow-x: hidden;
  overflow-y: auto;
  width: 100%;
  height: 100%;
  min-width: 100%;
  min-height: 100%;
}

.scroll-x {
  overflow-y: hidden;
  overflow-x: auto;
  width: auto;
  min-width: 100%;
  min-height: 100%;
}

.content-container {
  min-width: 100%;
  min-height: 100%;
  display: inline-block;
}

Puoi provarlo qui in Safari su iPhone.

In bocca al lupo!! 😉


: mani alzate: mani alzate:
cup_of

0

sembra divertente;)

Non discuterò se è ragionevole.

L'ho provato con RxJS:

  ngAfterViewInit() {
    const table = document.getElementById("table");

    const touchstart$ = fromEvent(table, "touchstart");
    const touchmove$ = fromEvent(table, "touchmove");
    const touchend$ = fromEvent(table, "touchend");

    touchstart$
      .pipe(
        switchMapTo(
          touchmove$.pipe(
            // tap(console.log),
            map((e: TouchEvent) => ({
              x: e.touches[0].clientX,
              y: e.touches[0].clientY
            })),
            bufferCount(4),
            map(calculateDirection),
            tap(direction => this.setScrollingStyles(direction)),
            takeUntil(touchend$)
          )
        )
      )
      .subscribe();
  }

Abbiamo BUFFER ogni 4 touchemoveevento e poi fare qualche calcolo altamente sofisticato con le coordinate dei quattro eventi ( map(calculateDirection)) che uscite RIGHT, LEFT, UPoDOWN e basato su che provo a scorrimento verticale o horicontal disattivare. Sul mio telefono Android in Chrome funziona in qualche modo;)

Ho creato un piccolo parco giochi , che potrebbe essere migliorato, riscritto, qualunque cosa ...

Saluti Chris

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.