Android Studio:在 ScrollView 中调用多个 Canvas 以显示 1 个绘图(canvas)

Android Studio: Calling multiple Canvas in ScrollView to display 1 drawing (canvas) after another

我正在为学校项目编写代码,其中必须加载数据文件(CSV 文件、文本文件等),应用程序将从获得的数据中将数据传递给自定义绘图视图和onDraw 方法将 draw/plot 基于数据的图形。

我的目标是让应用程序显示 2 个图形,一个接一个(堆叠)。加载第一组数据并绘制第一个图形。然后,加载的数据将用于不同方法中的不同计算。然后使用新数据再次调用自定义绘图视图以绘制第二张图。

当我 运行 应用程序时,两个图表都被绘制,但是因为图表的 x 轴和 y 轴被编码为在某些固定像素处绘制,所以第二个图表绘制在第一个图表之上因此只有第二张图是可见的。

有什么方法可以绘制 2 个图形,使其不重叠,而是在 ScrollView 中看起来堆叠在一起?

我的代码如下所示,但是我去掉了我认为不是很重要的计算。非常感谢任何帮助和指点!

MainActivity.java:

    @Override
    protected void onActivityResult(......) {
        super.onActivityResult(......);
        switch (1) {
            case 1:
                Graph graph = this.findViewById(R.id.graph1);
                graph.setData(data); // the loaded data is passed to Graph View
                Graph drawGraph2 = this.findViewById(R.id.graph2);
                graph2.setData(this.newCalculate(data));
                break;
        }
    }

Graph.java

    public  class Graph extends View {
    private Paint mPaint = new Paint();
    private final int zero = 700; // mark the 0 line of graph at 700 pixels


    public void setData(data){   
        ......
    }

    public Graph(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);

    }

    @Override
    protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);
    }

        @Override
        protected void onDraw(Canvas canvas) { 
        super.onDraw(canvas);

        plotUnit(canvas);    // plot points on graph

        axisLabel(canvas);    // label axis

        axisLine(canvas);     // draw axis

        xyAxisMarker(canvas);    // mark axis
    }

    private void plotUnit(Canvas canvas) {
        ......
        // Due to data having negative values, the graph is inverted and the 0 starts
        // of the graph is defined at 700 pixels (private final int zero)
    }

    private void axisLabel(Canvas canvas) {
        ......
    }

    private void axisLine(Canvas canvas, int inset) {
        ......
    }

    private void xyAxisMarker(Canvas canvas) {
        ......
    }

更新

activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <Button
                    android:id="@+id/loadbutton"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Open Data File" />

                <firstapp.drawtwograph.Graph
                    android:id="@+id/graph1"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent" />

                <firstapp.drawtwograph.Graph
                    android:id="@+id/graph2"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent" />
            </LinearLayout>
        </ScrollView>
    </LinearLayout>

您不能让两个视图的高度与 LinearLayout 垂直方向 内的 parent 高度匹配。这是不可能的,因为这些视图的高度必须等于 parent 高度,但同时,它们必须一个接一个地排列,导致 parent 高度的两倍。

如果您将 parent 的高度想象为 10dp,那么每个 Graph 视图也必须是 10dp,这意味着 parent 的高度必须是 20dp,而不是 10dp。这将永远循环,所以 Android 做了一件简单的事情:低于第一个 android:layout_height="match_parent" 的 child 视图的视图将具有高度 0dp 或者如果它们的高度是修复了它们将被绘制在布局之外并且不可见的问题。

示例

Android Studio IDE 中布局编辑器的设计选项卡的屏幕截图IDE。

在这里你可以看到:

  • 红色视图作为 parent 线性布局;
  • 紫色视图作为第一个 child 高度匹配它的 parent 高度;
  • 在布局之外绘制的轮廓视图,因为它被第一个 child 和 android:layout_height="match_parent" 推出;
  • 还有一个视图被压缩到 0 高度,因此不可见。你可以在XML代码中看到它。

XML 本例代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="100dp"
    android:background="@android:color/holo_red_light">

    <LinearLayout
        android:background="@color/colorPrimary"
        android:layout_width="60dp"
        android:layout_height="match_parent" <!-- this view's height is a problem -->
        android:orientation="vertical"/>

    <LinearLayout
        android:background="@android:color/holo_green_dark"
        android:layout_width="120dp"
        android:layout_height="match_parent" <!-- height is not fixed, then it will be 0 -->
        android:orientation="vertical"/>

    <LinearLayout
        android:background="@android:color/holo_green_light"
        android:layout_width="120dp"
        android:layout_height="40dp" <!-- height is fixed, it is outlined outside of a layout -->
        android:orientation="vertical"/>

</LinearLayout>

如何解决这个问题?

  1. 设置固定高度。作为测试尝试定义一个固定的高度,例如100dp;
  2. 重新设计您的布局。使用 RelativeLayoutConstraintLayout 相对于彼此定位视图,以便无论屏幕尺寸、比例、密度如何,它们始终可见。

修复方法示例

我个人比较喜欢ConstraintLayout,因为它在定位和适配方面非常强大

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/loadbutton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Open Data File"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <firstapp.drawtwograph.Graph
        android:id="@+id/graph1"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/graph2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/loadbutton" />

    <firstapp.drawtwograph.Graph
        android:id="@+id/graph2"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/graph1" />
</androidx.constraintlayout.widget.ConstraintLayout>

结果是(我使用了两个按钮而不是图形视图):

提示:

  • 如果要使用ScrollView则需要设置固定高度或在运行时定义高度。
  • 干掉private final int zero = 700; // mark the 0 line of graph at 700 pixels。不要直接使用像素值,因为它会导致 error-prone UI。这将是“对我的 phone 起作用,对另一个不起作用”的情况。使用视图的高度作为 0 行。