没有调用带有RelativeLayout和CustomView的Android片段 - onDraw

时间:2014-08-22 15:41:53

标签: android android-fragments android-canvas relativelayout android-custom-view

我有一个相对布局的片段 - 正确显示。 现在我尝试使用画布添加自定义视图 - 我可以在其中动态绘制。但是,如果我从自定义View调用drawConnectionLine方法,则不会调用自定义视图的onDraw方法。如果我不调用drawConnectionLine方法它可以工作。 我在创建视图后尝试在onResume方法中调用drawConnectionLine,但它没有帮助......

如何在初始化后动态绘制自定义视图而不会出现NullPointerException(因为onDraw没有被执行)?

这是我的片段代码( FragmentPlan.java ):

package de.tucais.svm.youplan;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import android.app.Activity;
import android.app.Fragment;
import android.content.ContentValues;
import android.graphics.Canvas;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class FragmentPlan extends Fragment
{
    // Define logging variables
    private static final String LOGCAT = "YP-FragmentPlan";
    private static final boolean D = true; // control debug-output

    Activity parentActivity;
    LibSVM svm = null;
    DatabaseController db;
    Controller controller = null;
    DrawView drawView = null;
    //Canvas drawCanvas = null;

    int firstTv_margin_top, firstTv_margin_left, firstTv_margin_right, firstTv_margin_bottom;
    int tv_margin_top, tv_margin_left, tv_margin_right, tv_margin_bottom;

    RelativeLayout planLayout = null;
    List<TextView> taskElements = new ArrayList<TextView>();

    public FragmentPlan()
    {

    }

    public void onResume()
    {
        super.onResume();
        computeResult();
    }

    @Override    
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.fragment_plan, container, false);
        controller = new Controller((MainActivity)getActivity());
        planLayout = (RelativeLayout)view.findViewById(R.id.relativeLayout_plan);

        // Translate the margin-values from dp to pixel
        firstTv_margin_left = getResources().getDimensionPixelSize(R.dimen.plan_firstTv_margin_left);
        firstTv_margin_top = getResources().getDimensionPixelSize(R.dimen.plan_firstTv_margin_top);
        firstTv_margin_right = getResources().getDimensionPixelSize(R.dimen.plan_firstTv_margin_right);
        firstTv_margin_bottom = getResources().getDimensionPixelSize(R.dimen.plan_firstTv_margin_bottom);
        tv_margin_left = getResources().getDimensionPixelSize(R.dimen.plan_tv_margin_left);
        tv_margin_top = getResources().getDimensionPixelSize(R.dimen.plan_tv_margin_top);
        tv_margin_right = getResources().getDimensionPixelSize(R.dimen.plan_tv_margin_right);
        tv_margin_bottom = getResources().getDimensionPixelSize(R.dimen.plan_tv_margin_bottom);

        // Create the DrawView and append it to the RelativeLayout
        drawView = new DrawView((MainActivity)getActivity());
        RelativeLayout.LayoutParams drawViewParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        drawView.setLayoutParams(drawViewParams);
        drawView.setId(View.generateViewId());

        planLayout.addView(drawView);
        //sendViewToBack(drawView);     
        if(D) Log.i(LOGCAT,"drawCanvas created...");

        if(D) Log.i(LOGCAT,"onCreateView finished...");
        return view;
    }

    private void computeResult()
    {
        List<ContentValues> result = controller.computeSequence();
        //displayResult(result.get(0));
        for(int i=0; i < result.size(); i++)
        {
            displayResultElement(result.get(i));
            if(i > 0)
            {
                if(D) Log.i(LOGCAT,"tried to draw connection for " + i + " time...");
                if(D) Log.i(LOGCAT,"DrawCanvas is null: " + drawView.isCanvasNull()); //-> returns true
                drawView.drawConnectionLine(taskElements, i); //-> this call causes the error
                if(D) Log.i(LOGCAT,"succesfully drawed connection nr" + i + "...");
            }
        }
    }

    private void displayResultElement(ContentValues resultElement)
    {
        // Create a new element
        TextView newElement = new TextView((MainActivity)getActivity());
        newElement.setId(View.generateViewId());
        newElement.setBackground(getResources().getDrawable(R.drawable.shape_circle));

        // Fill the new Element with its content
        Set<Entry<String, Object>> s = resultElement.valueSet();
        Iterator<Entry<String, Object>> itr = s.iterator();
        Map.Entry<String, Object> me = (Map.Entry<String, Object>)itr.next();
        newElement.append(me.getKey().toString()+": " + me.getValue().toString());
        while(itr.hasNext())
        {
            me = (Map.Entry<String, Object>)itr.next();
            newElement.append("\n"+me.getKey().toString()+": " + me.getValue().toString());
        }
        // After filling the new element with content append it to its parent view element
        planLayout.addView(newElement);
        // add the element to the list
        taskElements.add(newElement);
        // Position the new element on the screen       
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)newElement.getLayoutParams();
        // if there is more than the current element in the list position relative to the predecessor
        if(taskElements.size() > 1)
        {
            params.addRule(RelativeLayout.BELOW, taskElements.get(taskElements.size()-2).getId());
            params.addRule(RelativeLayout.ALIGN_LEFT, taskElements.get(taskElements.size()-2).getId());
            params.setMargins(tv_margin_left, tv_margin_top, tv_margin_right, tv_margin_bottom);
        }
        else
        {
            params.setMargins(firstTv_margin_left, firstTv_margin_top, firstTv_margin_right, firstTv_margin_bottom);
        }       
        newElement.setLayoutParams(params);
    }

    private static void sendViewToBack(final View v)
    {
        final ViewGroup parent = (ViewGroup)v.getParent();
        if (parent != null)
        {
            parent.removeView(v);
            parent.addView(v, 0);
        }
    }
}

这是relativeLayout的我的xml文件( fragment_plan.xml ):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/relativeLayout_plan"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="2dp"
    tools:context=".MainActivity" >

</RelativeLayout>

这是我的CustomView( DrawView.java ):

package de.tucais.svm.youplan;

import java.util.List;

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

public class DrawView extends View
{
    // Define logging variables
    private static final String LOGCAT = "YP-DrawView";
    private static final boolean D = true; // control debug-output

    private Canvas drawCanvas = null;

    public DrawView(final Context context)
    {
        super(context);
        if(D) Log.i(LOGCAT,"DrawView constructor called... ");
    }

    @Override
    protected void onMeasure(int w, int h)
    {
        if(D) Log.d(LOGCAT,"onMeasure with w= " + w + " and h= " + h + " called...");
        setMeasuredDimension(w, h);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        if(D) Log.i(LOGCAT,"onDraw called... ");
        this.drawCanvas = canvas;
        if(D) Log.d(LOGCAT,"drawCanvas still empty? " + (this.drawCanvas == null));
    }

    /*
     * Method which draws a connection line between two graphical elements on the screen
     * @param {List<TextView>} taskElements - a list of all TextView-elements
     * @param {int} nr - the number of the destination element
     */
    public void drawConnectionLine(List<TextView> taskElements, int nr)
    {
        if(D) Log.i(LOGCAT,"drawConnectionLine called... ");

        TextView currentElement = taskElements.get(nr);
        TextView prevElement = null;
        try
        {
            prevElement = taskElements.get(nr-1);
        }
        catch(Exception e)
        {
            Log.e(LOGCAT, "No predacessor!!!");
        }

        int startX = computeCenter(prevElement);
        int startY = prevElement.getBottom();
        int stopX = computeCenter(currentElement);
        int stopY = currentElement.getTop();

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLACK);
        this.drawCanvas.drawLine(startX, startY, stopX, stopY, paint); //-> this.drawCanvas == null => Why???
    }

    private int computeCenter(View element)
    {
        int result = 0;
        if(element != null)
        {
            int right = element.getRight();
            result = right - (element.getWidth()/2);
        }
        return result;
    }

    public void emptyCanvas()
    {
        // Clear the canvas
        this.drawCanvas.drawColor(Color.TRANSPARENT);
    }

    public boolean isCanvasNull()
    {
        return this.drawCanvas == null;
    }
}

如果有人可以解释一下,为什么在调用drawConnectionLine方法时没有调用DrawView的onDraw方法,这是非常好的,这就是FragmentPlan.java第95行中NullPointerException的原因。

提前致谢!!!

1 个答案:

答案 0 :(得分:0)

是的,似乎系统假定视图宽度和高度为零,因此没有调用onDraw()。您可以覆盖View类中的onMeasure(int,int)方法以指定视图的宽度和高度。

链接: Custom onDraw() method not called