Salut
-----
J'ai déjà utilisé des scrolls verticaux dans certaines applications, comme par exemple naviguer dans une maison (passage d'un étage à l'autre par scroll vertical, et d'une pièce à l'autre en horizontal)
Si on se limite à un seul sens de déplacement (dans ton cas: vertical) c'est relativement simple.
Il y a deux étapes:
La première étape est de transformer visuellement le scroll horizontal en scroll vertical. Pour ça, on utilise un PageTransformer spécifique, dérivé de ViewPager.PageTransformer, et on surcharge sa méthode transformPage()
Cette méthode fournit deux paramètres: La page concernée et le déplacement relatif fait par le ViewPager, exprimé en largeur d'écran.
Et donc la page centrée à l'écran a un déplacement de 0, un déplacement de -1 correspond à une page complètement décalée à gauche et de +1 complètement décalée à droite (et donc invisibles)
La méthode est appelée par le ViewPager pour toutes les pages existantes, visibles ou non, sachant qu'une page qui est totalement visible à l'écran a donc un déplacement de 0, et une vue partiellement visible a un déplacement dans l'intervalle ouvert ]-1,+1[
On peut déjà, pour éviter de tout calculer, rendre toute vue avec déplacement <=-1 ou >=1 invisible, on ne s'occupe dès lors plus que des vues partiellement visibles (celles en cours de scroll). L'astuce consiste à commencer par contrecarrer le déplacement horizontal par défaut: Vu qu'on reçoit le déplacement relatif, il suffit d'affecter à la page un déplacement inverse dont la valeur en pixel vaut l'inverse du déplacement multiplié par la largeur d'écran. Ainsi, les fragments partiellement visibles sont bloqués horizontalement au centre de l'écran (et donc superposés). Reste ensuite simplement à affecter à chaque page un déplacement vertical qui est le déplacement relatif multiplié par la hauteur d'écran.
Ça donne quelque chose du style (en Java):
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| ///////////////////////////////////////////////////////////////////////////////
// VERTICAL PAGER TRANSFORMER //
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// Le fragment se déplace verticalement au lieu d'horizontalement
//-----------------------------------------------------------------------------
public class VerticalPageTransformer implements ViewPager.PageTransformer
{
@Override
public void transformPage(View view, float position)
{
// Fragment hors écran vers la gauche
if (position < -1) // [-infini,-1[
{
view.setAlpha(0);
}
// Fragment dans la zone visible
else if (position <= 1) // [-1,1]
{
view.setAlpha(1); // visible
view.setTranslationX(view.getWidth() * -position); // on bloque le mouvement horizontal
float yPosition = position * view.getHeight(); // calcul de la position verticale
view.setTranslationY(yPosition); // on applique la translation verticale
}
// Fragment hors zone visible par la droite
else // ]1,infini]
{
view.setAlpha(0);
}
}
} |
Le code est presque plus court que l'explication, mais vu que le but est d'apprendre...
Quand on a fait ça, on obtient un déplacement visuel vertical à l'écran, mais ce déplacement s'effectue par un glissement du doigt horizontal.
La seconde étape consiste donc à inverser le mouvement du doigt.
Et ça, ça se fait de façon aussi simple, en dérivant le ViewPager et en surchargeant les méthodes onInterceptTouchEvent() et onTouchEvent()
Ces méthodes reçoivent les déplacements du doigt x et y. L'astuce consiste à fournir à la classe parent le déplacement reçu avec inversion de X et de Y. Il faut juste prendre la précaution de recalculer x et y en fonction de la hauteur et la largeur de l'écran: Un déplacement en X sur toute la largeur de l'écran doit correspondre à un déplacement en Y sur toute la hauteur de l'écran. De la sorte, le ViewPager croit que lorsque l'utilisateur déplace son doigt verticalement que ce déplacement est en réalité horizontal
Et donc, on obtient un truc du genre:
Code:
1 2 3 4 5 6
| public boolean onInterceptTouchEvent(MotionEvent event)
{
boolean result = super.onInterceptTouchEvent(swapXY(event)); // inverser x et y
swapXY(event); // On remet à l'endroit pour classes filles
return result; // On retourne résultat
} |
Code:
1 2 3 4 5 6
| public boolean onTouchEvent(MotionEvent event)
{
boolean result = super.onTouchEvent(swapXY(event)); // on inverse x et y
swapXY(event);
return result;
} |
Le swap est la simple inversion avec mise à l'échelle:
Code:
1 2 3 4 5 6 7 8 9 10 11
| private MotionEvent swapXY(MotionEvent event)
{
float width = getWidth(); // largeur
float height = getHeight(); // hauteur
float newX = (event.getY() / height) * width; // x = y remis à l'échelle
float newY = (event.getX() / width) * height; // y = x remis à l'échelle
event.setLocation(newX, newY); // appliquer modifs
return event; // retourner event modifié
} |
Et voilà un scroll vertical: ça fonctionne aussi pour n'importe quel type de scroll, pour changer les transitions (cube, perspectives etc), et ça permet même (mais il faut un peu plus de code) d'avoir un scroll 2D (horizontal ET vertical)
On peut faire un peu plus court, mais j'ai conservé l'aspect didactique
Je te laisse chercher sur la façon d'utiliser un ViewPager et un ViewPagerTransformer, c'est tout sauf compliqué.
J'espère que ça t'aura aidé :)
A+
Claude