我有一个相对布局的片段 - 正确显示。 现在我尝试使用画布添加自定义视图 - 我可以在其中动态绘制。但是,如果我从自定义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的原因。
提前致谢!!!
答案 0 :(得分:0)
是的,似乎系统假定视图宽度和高度为零,因此没有调用onDraw()。您可以覆盖View类中的onMeasure(int,int)方法以指定视图的宽度和高度。