Défilement sur une grande canvas

J’ai besoin d’aide pour comprendre les principes de base du défilement des éléments dessinés sur une canvas dans Android. Supposons que je souhaite créer une chronologie où le temps à 0 est le sumt d’une visualisation et au fur et à mesure que le temps augmente, la chronologie continue à être affichée sous le point précédent. Si je souhaite rendre ceci sur Android, je sais que je pourrais simplement créer un tas d’éléments sur une canvas en remplaçant onDraw (). Cependant, supposons que la visualisation soit plus grande que ce que l’écran permet.

Par exemple, dans la première image ci-dessous, la grande boîte noire contient la totalité de la canvas telle que je la rende. Je crée une ligne bleue qui monte et descend verticalement ainsi que plusieurs rectangles jaunes, verts et bleus. La boîte rouge représente l’écran d’Android qui rend la visualisation. A l’ouverture, tous les éléments sont dessinés, mais seuls les éléments contenus dans la zone rouge s’affichent à l’écran.

Before_Scroll

Désormais, si l’utilisateur doit faire défiler l’écran vers le bas, les éléments apparaissant initialement sous la zone rouge sont visibles tandis que les éléments sortis des limites de la zone rouge ne sont plus visibles, comme indiqué dans la deuxième image.

After_Scroll

Je crois que je dois utiliser des scrollables mais je ne sais pas trop comment faire. J’ai lu cette page http://developer.android.com/training/custom-views/custom-drawing.html en expliquant comment créer vos propres images client et cette page http://developer.android.com/training /custom-views/making-interactive.html expliquant comment rendre l’interface utilisateur interactive, mais je pense qu’il me manque quelque chose.

Un exemple de code illustrant ce problème (c’est fondamental, supposons qu’il existe une logique dictant O les zones / lignes vont, etc.) est le suivant:

package com.example.scrolltest; import com.example.scrolltest.Draw; import android.os.Bundle; import android.app.Activity; import android.graphics.Color; public class MainActivity extends Activity { Draw draw; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); draw = new Draw(this); draw.setBackgroundColor(Color.WHITE); setContentView(draw); } } 

et

 package com.example.scrolltest; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.view.View; public class Draw extends View { Paint paint = new Paint(); public Draw(Context context) { super(context); } @Override public void onDraw(Canvas canvas) { paint.setColor(Color.GREEN); canvas.drawRect(30, 30, 90, 200, paint); paint.setColor(Color.BLUE); canvas.drawLine(100, 20, 100, 1900, paint); paint.setColor(Color.GREEN); canvas.drawRect(200, 2000, 400, 3000, paint); } } 

Ce que je ne peux pas comprendre, c’est la façon dont j’utilise un défilement pour faire défiler les rectangles qui se trouvent en dehors de l’écran. Je ne sais pas non plus si j’ai commencé correctement ou si je devrais utiliser drawables à la place …

Méthode simple (si la hauteur requirejse n’est pas très grande).

Utilisez une ScrollView et ajoutez-y votre vue Draw. Calculez la hauteur requirejse pour cette vue dans onMeasure.

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); draw = new Draw(this); draw.setBackgroundColor(Color.WHITE); ScrollView scrollView = new ScrollView(this); scrollView.addView(draw); setContentView(scrollView); } public class Draw extends View { Paint paint = new Paint(); public Draw(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Compute the height required to render the view // Assume Width will always be MATCH_PARENT. int width = MeasureSpec.getSize(widthMeasureSpec); int height = 3000 + 50; // Since 3000 is bottom of last Rect to be drawn added and 50 for padding. setMeasuredDimension(width, height); } @Override public void onDraw(Canvas canvas) { paint.setColor(Color.GREEN); canvas.drawRect(30, 30, 90, 200, paint); paint.setColor(Color.BLUE); canvas.drawLine(100, 20, 100, 1900, paint); paint.setColor(Color.GREEN); canvas.drawRect(200, 2000, 400, 3000, paint); } } 

Une autre solution consiste à utiliser des valeurs X / Y décalées.

La façon dont vous gérez les valeurs de décalage dépend de vous, mais je préfère utiliser une classe que j’appelle Camera . L’access devrait être statique.

 public void render(Canvas c){ c.drawRect(100 - offsetX, 100 - offsetY, 120 - offsetX, 120 - offsetY, Paints.BLUE); } 

Et pour faire un panoramique sur la canvas:

 float x, y; @Override public boolean onTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_DOWN){ x = ev.getX(); y = ev.getY(); }else if (ev.getAction() == MotionEvent.ACTION_MOVE) { float currX = ev.getX(); float currY = ev.getY(); float newOffsetX = (x - currX), newOffsetY = (y - currY); //The next two if-statements are to add sensitivity to the scrolling. //You can drop these if you don't plan on having touch events //with pressing. Pressing works without this as well, but the canvas may move slightly //I use DP to handle different screen sizes but it can be replaced with pixels. c is a context-instance if (newOffsetY < Maths.convertDpToPixel(2, c) && newOffsetY > -Maths.convertDpToPixel(2, c)) newOffsetY = 0; if (newOffsetX < Maths.convertDpToPixel(2, c) && newOffsetX > -Maths.convertDpToPixel(2, c)) newOffsetX = 0; offsetX += newOffsetX; offsetY += newOffsetY; x = ev.getX(); y = ev.getY(); } return true; } 

Et un exemple de Camera-class:

 public class Camera{ public static float offsetX, offsetY; //The constructor. ix and iy is the initial offset. Useful if you are creating a game and need to change the initial offset to center around a starting position. //Most of the time it will be enough to set the values to 0 public Camera(float ix, float iy){ this.offsetX = ix; this.offsetY = iy; } }