Прокрутка по большому холсту
Мне нужна помощь, чтобы понять основы прокрутки элементов, которые нарисованы на холсте в Android. Предположим, я хочу создать временную шкалу, где время в 0 является вершиной визуализации, и по мере увеличения времени шкала продолжает отображаться ниже предыдущей точки. Если я хочу сделать это на Android, я знаю, что могу просто создать кучу элементов на холсте, переопределив onDraw(). Однако предположим, что визуализация больше, чем позволяет экран.
Например, на первом рисунке ниже большой черный ящик содержит весь холст, когда я его делаю. Я создаю синюю линию, которая работает вертикально вверх и вниз, а также несколько желтых, зеленых и синих прямоугольников. Красная рамка представляет собой экран Android, который визуализирует визуализацию. Когда он изначально открывается, все элементы рисуются, но на экране появляются только элементы, содержащиеся в красном поле.
![Before_Scroll]()
Теперь, если пользователь должен прокручивать вниз, элементы, которые первоначально появились под красным полем, находятся в поле зрения, в то время как элементы, которые вышли из границ красного квадрата, больше не видны, как показано на втором рисунке.
![After_Scroll]()
Я считаю, что мне нужно использовать прокрутки, но я совершенно потерял, как это сделать. Я прочитал эту страницу http://developer.android.com/training/custom-views/custom-drawing.html, объяснив, как создать свои собственные изображения клиентов, и эта страница http://developer.android.com/training/custom-views/making-interactive.html, объясняя, как сделать интерактивный интерфейс интерактивным, но я думаю, что что-то не хватает.
Образец кода, который иллюстрирует эту проблему (это основной, предположим, что существует логика, диктующая WHERE, строки/линии идут и т.д.) выглядит следующим образом:
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);
}
}
и
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);
}
}
Что я не могу понять, так это то, как я использую прокручиваемую прокрутку вниз до прямоугольников, которые находятся вне экрана. Я также не уверен, что я начал это правильно или должен использовать drawables вместо...
Ответы
Ответ 1
Простой метод (если требуемая высота не очень большая).
Используйте ScrollView и добавьте в него вид Draw. Вычислите требуемую высоту для этого вида в 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);
}
}
Ответ 2
Альтернативой может быть использование значений смещения X/Y.
Как вы обрабатываете значения смещения, зависит от вас, все, хотя я предпочитаю использовать класс I, вызывающий Camera
. Доступ должен быть статичным.
public void render(Canvas c){
c.drawRect(100 - offsetX, 100 - offsetY, 120 - offsetX, 120 - offsetY, Paints.BLUE);
}
И для панорамирования холста:
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;
}
И образец класса камеры:
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;
}
}