onDraw не вызывается для пользовательского представления, полученного из представления в макете

#android

#Android

Вопрос:

У меня есть пользовательское представление………

 package com.yasir.canvasTest;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.util.Log;
import android.view.View;


public class GraphView extends View {

    private static final String TAG = "GraphView";
    public static boolean BAR = true;
    public static boolean LINE = false;

    private Paint paint;
    private float[] values;
    private String[] horlabels;
    private String[] verlabels;
    private String title;
    private boolean type;
    public Canvas tmpCanvas = null;

    public GraphView(Context context, float[] values, String title, String[] horlabels, String[] verlabels) {
        super(context);
        //setScrollContainer(true);
        Log.v(TAG,"On GraphView==>");




        paint = new Paint();

        setWillNotDraw(false);
        requestLayout();
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {




        Log.v(TAG,"<==On Draw");

/// drawing code here
        invalidate();
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.v(TAG,"On onMeasure==>");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(
                parentWidth * 2, parentHeight);
    }

}
  

……………
Действие: onCreate
……………

 setContentView(R.layout.horscroll);

HorizontalScrollView hsView = (HorizontalScrollView) findViewById(R.id.hzsv);

LinearLayout ll = (LinearLayout) findViewById(R.id.linearParent);
ll.removeAllViews();


// create custom view and add to laywout
GraphView graphView = new GraphView(this, values, "GraphViewDemo",horlabels, verlabels, GraphView.LINE);


hsView.requestLayout();
hsView.setWillNotDraw(false);

ll.requestLayout();
ll.setWillNotDraw(false);
ll.addView(graphView);
  

…………………
Xml
………………..

 <?xml version="1.0" encoding="utf-8"?>

<HorizontalScrollView
 android:id="@ id/hzsv"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout android:id="@ id/linearParent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"></LinearLayout>
 </HorizontalScrollView>
  

………………

С уважением, Ясир Первез

Ответ №1:

Попробуйте проверить с помощью Hierarchy Viewer, что происходит. Я подозреваю, что ваше представление не отображается, потому что оно имеет ширину 0, и это может быть по двум причинам (одной или обеим):

  • вы не устанавливаете ничего LinearLayout.LayoutParams в своем пользовательском представлении перед добавлением его в макет, и я не уверен, что значения по умолчанию относятся к типу «заполняющий родитель»;
  • ваш onMeasure() неполный, он также должен учитывать режим ( UNSPECIFIED , EXACTLY , AT_MOST ), который также будет зависеть от параметров макета. Нет гарантии, что getSize() возвращает родительский размер, и, поскольку подразумевается фреймворк, вы даже не должны знать, произойдет ли это.

(предложение @slund, вероятно, тоже будет полезным)

Комментарии:

1. хороший момент в параметрах макета. Я понимаю, что я добавил layoutparams в свой тест, поэтому я вернулся и протестировал без этого. В любом случае меня просили измерить нулевую ширину. Это действительно озадачивает меня. Я даже помещаю scrollview в линейный макет с шириной «fill_parent» и ВСЕ равно получаю нулевое значение. Мне нужно разобраться в этом подробнее. FillViewport помогает в любом случае, но я просто пока не удовлетворен. Очевидно, что мне есть чему поучиться в scrollviews 🙂

2. @slund: в документах говорится, что onMeasure() это может вызываться несколько раз, даже с размерами 0-0, чтобы увидеть, какого размера хотел бы быть вид. Смотрите Вид , макет раздела.

3. ОК. Возвращаюсь к чтению кода, и теперь я понимаю, что происходит. HorizontalScrollView переопределяет measureChild и measureChildWithMargins и принудительно присваивает ширине MeasureSpec значение MeasureSpec. НЕ УКАЗАНО. Если вы установите для FillViewport значение true, child.measure вызывается напрямую с помощью MeasureSpec.ТОЧНО и ширины окна просмотра. Таким образом, любое представление в HorizontalScrollView ДОЛЖНО обрабатывать MeasureSpec. НЕУКАЗАННЫЙ тип в их onMeasure и определяет их собственную ширину. Независимо от того, что вы вводите в XML для layout_width.

Ответ №2:

Ваш GraphView измеряется шириной 0 (ноль). Затем вы запрашиваете, чтобы для него было установлено значение 2 * width, которое по-прежнему равно нулю. Логика рисования оптимизирует не запрашивать представление нулевой ширины для рисования.

Вероятно, вы хотите попросить HorizontalScrollView заполнить всю ширину представления с помощью android:FillViewport=»true», т.Е.:

 <?xml version="1.0" encoding="utf-8"?>

 <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@ id/hzsv"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:fillViewport="true">
    <LinearLayout 
        android:id="@ id/linearParent"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    </LinearLayout>
</HorizontalScrollView>
  

Также смотрите ответ @bigstones. Вам действительно нужно обрабатывать все типы MeasureSpec (НЕУКАЗАННЫЕ, AT_MOST, ТОЧНО). Установка FillViewport=»true» позволяет вызвать onMeasure с ТОЧНЫМ указанием типа и ширины окна просмотра.

Комментарии:

1. Спасибо всем за такую хорошую поддержку, это было очень полезно. моя проблема решена. и узнал кое-что о scrollviews