Android Studio: вызов нескольких Canvas в ScrollView для отображения 1 рисунка (холста) за другим

Я пишу код для школьного проекта, где нужно загрузить файл данных (файл CSV, текстовый файл и т. д.), и из полученных данных приложение передаст данные в пользовательское представление рисования, а метод onDraw будет рисовать /построить график на основе данных.

Моя цель состоит в том, чтобы приложение отображало 2 графика один за другим (с накоплением). Загружается первый набор данных и строится первый график. Затем загруженные данные используются для другого расчета другим методом. Затем снова вызывается пользовательское представление отрисовки с новыми данными для построения второго графика.

Когда я запускаю приложение, рисуются обе диаграммы, но поскольку оси x и y графика закодированы для рисования в определенных фиксированных пикселях, второй график рисуется поверх первого, и поэтому виден только второй график.

Есть ли способ нарисовать 2 графика, чтобы они не перекрывались и вместо этого казались сложенными в ScrollView?

Мой код показан ниже, но я избавился от вычислений, которые я считаю не очень важными. Любая помощь и указатели будут очень признательны!

Основная активность.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;
        }
    }

График.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>

person Jaclyn    schedule 15.07.2020    source источник
comment
Опубликуйте свой XML-макет. Проблема может быть там.   -  person Jenea Vranceanu    schedule 15.07.2020
comment
@JeneaVranceanu Я отредактировал сообщение и добавил свой макет XML   -  person Jaclyn    schedule 17.07.2020


Ответы (1)


Высота двух представлений не может совпадать с высотой родителя внутри LinearLayout с вертикальной ориентацией. Это невозможно, потому что высота этих видов должна быть равна высоте родителя, но в то же время они должны быть упорядочены один за другим, что приводит к удвоению высоты родителя.

Если вы представляете себе высоту родителя как 10dp, то каждое из Graph представлений также должно быть 10dp, что означает, что высота родителя должна быть 20dp, а не 10dp. Это будет циклически повторяться вечно, поэтому Android делает простую вещь: представления, которые идут ниже первого дочернего представления с android:layout_height="match_parent", будут иметь высоту 0dp или, если их высота фиксирована, они будут отображаться за пределами макета и не будут видны.

Пример

Пример проблемы

Скриншот с вкладки "Дизайн" редактора макетов в Android Studio IDE.

Здесь вы можете увидеть:

  • красный вид в качестве родительского линейного макета;
  • фиолетовый вид как первый дочерний элемент с высотой, соответствующей высоте его родителя;
  • контурный вид, который рисуется за пределами макета, потому что он вытесняется первым дочерним элементом с 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. Измените макет. Используйте RelativeLayout или ConstraintLayout для позиционирования видов относительно друг друга, чтобы они всегда были видны, независимо от размера экрана, соотношения сторон и плотности.

Пример как исправить

Я лично предпочитаю 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. Не используйте значения пикселей напрямую, так как это приведет к возникновению ошибок в пользовательском интерфейсе. Будет в случае работы на моем телефоне, на другом не работает. Используйте высоту представления в качестве нулевой строки.
person Jenea Vranceanu    schedule 17.07.2020