我需要一些帮助来理解滚动到Android中画布的项目的基本原理。假设我想创建一个时间轴,其中0的时间是可视化的顶部,随着时间的增加,时间轴继续呈现在前一点之下。如果我想在Android上渲染这个,我知道我可以通过覆盖onDraw()在画布上创建一堆项目。但是,假设可视化大于屏幕允许的可视化。
例如,在下面的第一张图片中,大黑框在我渲染时包含整个画布。我创建了一条垂直上下运行的蓝线以及几个黄色,绿色和蓝色矩形。红色框表示呈现可视化的Android屏幕。在最初打开时,所有项目都会被绘制,但只有红色框中包含的项目才会显示在屏幕上。
现在,如果用户要向下滚动,最初出现在红色框下方的项目将在视图中,而已经超出红色框范围的项目将不再可见,如第二张图片所示。
我相信我需要使用滚动条,但我很遗憾该怎么做。我已经阅读了这个页面http://developer.android.com/training/custom-views/custom-drawing.html,解释了如何创建自己的客户图像,这个页面http://developer.android.com/training/custom-views/making-interactive.html解释了如何使UI交互,但我想我错过了一些东西。
说明这个问题的示例代码(这是基本的,假设有逻辑指示框/行的位置等)如下:
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 ......
答案 0 :(得分:20)
简单方法(如果所需的高度不是很大)。
使用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);
}
}
答案 1 :(得分:1)
替代方案可以是使用偏移X / Y值。
你如何处理偏移值取决于你,虽然我更喜欢使用我称之为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;
}
示例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;
}
}