2017-02-28 29 views
0

我想创建一个绘制应用程序。为此,我创建了一个自定义DrawingView。要在绘图期间启用其他选项,CustomView应该包含在特定区域的activity_main.xml中。Android CustomView集成在片段中

public class MainActivity extends AppCompatActivity { 

DrawingView dv ; 
private Paint mPaint; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    mPaint = new Paint(); 
    mPaint.setAntiAlias(true); 
    mPaint.setDither(true); 
    mPaint.setColor(Color.GREEN); 
    mPaint.setStyle(Paint.Style.STROKE); 
    mPaint.setStrokeJoin(Paint.Join.ROUND); 
    mPaint.setStrokeCap(Paint.Cap.ROUND); 
    mPaint.setStrokeWidth(12); 

    dv = new DrawingView(this, mPaint); 
    setContentView(R.layout.activity_main); 
} 
} 

public class DrawingView extends View { 

public int width; 
public int height; 
private Bitmap mBitmap; 
private Canvas mCanvas; 
private Path mPath; 
private Paint mBitmapPaint, mPaint; 
Context context; 
private Paint circlePaint; 
private Path circlePath; 

public DrawingView(Context c, Paint pPaint) { 
    super(c); 
    context=c; 

    mPaint = pPaint; 
    mPath = new Path(); 
    mBitmapPaint = new Paint(Paint.DITHER_FLAG); 
    circlePaint = new Paint(); 
    circlePath = new Path(); 
    circlePaint.setAntiAlias(true); 
    circlePaint.setColor(Color.BLUE); 
    circlePaint.setStyle(Paint.Style.STROKE); 
    circlePaint.setStrokeJoin(Paint.Join.MITER); 
    circlePaint.setStrokeWidth(4f); 
} 

@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    super.onSizeChanged(w, h, oldw, oldh); 

    mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
    mCanvas = new Canvas(mBitmap); 
} 

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

    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); 
    canvas.drawPath(mPath, mPaint); 
    canvas.drawPath(circlePath, circlePaint); 
} 

private float mX, mY; 
private static final float TOUCH_TOLERANCE = 4; 

private void touch_start(float x, float y) { 
    mPath.reset(); 
    mPath.moveTo(x, y); 
    mX = x; 
    mY = y; 
} 

private void touch_move(float x, float y) { 
    float dx = Math.abs(x - mX); 
    float dy = Math.abs(y - mY); 
    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { 
     mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); 
     mX = x; 
     mY = y; 

     circlePath.reset(); 
     circlePath.addCircle(mX, mY, 30, Path.Direction.CW); 
    } 
} 

private void touch_up() { 
    mPath.lineTo(mX, mY); 
    circlePath.reset(); 
    // commit the path to our offscreen 
    mCanvas.drawPath(mPath, mPaint); 
    // kill this so we don't double draw 
    mPath.reset(); 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    float x = event.getX(); 
    float y = event.getY(); 

    switch (event.getAction()) { 
     case MotionEvent.ACTION_DOWN: 
      touch_start(x, y); 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      touch_move(x, y); 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_UP: 
      touch_up(); 
      invalidate(); 
      break; 
    } 
    return true; 
} 
} 

<?xml version="1.0" encoding="utf-8"?> 
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 
xmlns:tools="http://schemas.android.com/tools" 
 
android:id="@+id/activity_main" 
 
android:layout_width="match_parent" 
 
android:layout_height="match_parent" 
 
android:paddingBottom="@dimen/activity_vertical_margin" 
 
android:paddingLeft="@dimen/activity_horizontal_margin" 
 
android:paddingRight="@dimen/activity_horizontal_margin" 
 
android:paddingTop="@dimen/activity_vertical_margin" 
 
android:gravity="center" 
 
tools:context="de.sentoon.touchtesterv4.MainActivity" 
 
android:orientation="vertical"> 
 

 
<TextView 
 
    android:layout_width="match_parent" 
 
    android:layout_height="wrap_content" 
 
    android:text="Hello World!" /> 
 

 
<de.sentoon.touchtesterv4.DrawingView 
 
    android:layout_width="match_parent" 
 
    android:layout_height="150sp" /> 
 
</LinearLayout>

但如果我试试这个,总有抛出

FATAL EXCEPTION: main 
       Process: de.sentoon.touchtesterv4, PID: 11743 
       java.lang.RuntimeException: Unable to start activity ComponentInfo{de.sentoon.touchtesterv4/de.sentoon.touchtesterv4.MainActivity}: android.view.InflateException: Binary XML file line #20: Binary XML file line #20: Error inflating class de.sentoon.touchtesterv4.DrawingView 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2702) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2788) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1503) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6209) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
       Caused by: android.view.InflateException: Binary XML file line #20: Binary XML file line #20: Error inflating class de.sentoon.touchtesterv4.DrawingView 
       Caused by: android.view.InflateException: Binary XML file line #20: Error inflating class de.sentoon.touchtesterv4.DrawingView 
       Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet] 
        at java.lang.Class.getConstructor0(Class.java:2204) 
        at java.lang.Class.getConstructor(Class.java:1683) 
        at android.view.LayoutInflater.createView(LayoutInflater.java:618) 
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:787) 
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727) 
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:858) 
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:518) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:426) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:377) 
        at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:288) 
        at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140) 
        at de.sentoon.touchtesterv4.MainActivity.onCreate(MainActivity.java:27) 
        at android.app.Activity.performCreate(Activity.java:6745) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1134) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2655) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2788) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1503) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6209) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

感谢您的帮助的InflateException。

+0

在家长线性布局标签的xmlns =添加此:定制=“http://schemas.android.com/apk/res-auto” – Jamil

回答

0

产生的原因:java.lang.NoSuchMethodException:类android.content.Context,接口android.util.AttributeSet]

您没有足够的声明构造。

通常自定义视图至少有2个构造函数。一个接受Context,另一个ContextAttributeSet

public class DravingView extends View { 
    public DravingView(final Context context) { 
     super(context); 
    } 

    public DravingView(final Context context, final AttributeSet attrs) { 
     super(context, attrs); 
    } 
} 

为什么我需要这个构造函数?

首先对xml进行解析,然后创建相应的类对象。解析文件xml后,框架会尝试使用xml中的应用参数为您创建DrawingView对象。这些参数正通过AttributeSet传递。但只要它在DrawingView类中找不到这样的构造函数,就会崩溃。

+0

谢谢!如果我添加了第二个构造函数,并在构造函数中设置了paint default! – Dawed

+0

好!作为社区的新手 - 当您收到问题的答案时,您应该将其标记为已解决。 – azizbekian

0

DrawingView构造改成这样

public DrawingView(Context c, AttributeSet attr) { 
    super(c, attr); 
    context=c; 
} 

此方法添加到您的DrawingView

public void setPaint(Paint pPaint) { 
     mPaint = pPaint; 
    } 

添加ID到工程视图中的XML <de.sentoon.touchtesterv4.DrawingView android:id="@+id/drawingView" android:layout_width="match_parent" android:layout_height="150sp" />

然后初始化drawingView这样 dv = (DrawingView) findViewById(R.id.drawingView);

然后设置您的油漆像这样的活动 dv.setPaint(mPaint);

+0

感谢您的回答! 但是,如果我试过这个,它调用 java.lang.NullPointerException:尝试在空对象引用 – Dawed

+0

上调用虚拟方法'void de.sentoon.touchtesterv4.DrawingView.setPaint(android.graphics.Paint)'你初始化了' DrawingView'首先像这样'dv =(DrawingView)findViewById(R.id.drawingView);'然后调用set paint方法。如果是的话,你在XML中添加id到drawingView,并且这是你的'DrawingView'' de.sentoon.touchtesterv4.DrawingView'因为也可能是问题的路径...如果你仍然有问题,那么发布完整的'活动“,”DrawingView“和布局文件 –