手指绘画程序存在问题。在这个程序中,我实现了两个片段,我已经意识到我的绘图片段,包含画布和支持绘图,不显示画布,还有其他问题。我的意识与我注意到,当我编写一个新类来扩展View时(因为片段不支持扩展视图本身),我没有实例化该类。我在片段中创建了一个类的实例,但是这个实例需要一个Context作为参数,而且我不确定要使用哪个上下文。我尝试过使用' getActivity()'作为上下文,但这不起作用,使程序挂起(在调试中)或崩溃(在正常模式下)。我应该在这个类实例化的上下文中使用什么?
片段代码:
package com.example.chris.drawingtest;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import com.example.chris.drawingtest.R;
/**
* Created by Chris on 11/28/2014.
*/
public class DrawingFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d("onCreateView: ","This ran successfully");
return inflater.inflate(R.layout.fragment_drawing, container, false);
}
private class DrawView extends View {
private Path drawpath = new Path();
private Paint drawpaint = new Paint();
private Paint canvaspaint;
private Canvas drawcanvas;
private Bitmap canvasBitmap;
private int paintColor = 0xFF000000; //opaque black for pencil
private int canvasColor = 0xFFFFFFFF; //pure white for canvas
public DrawView(Context context) {
super(context);
Log.d("DrawView: ", "method is called");
drawpaint.setColor(paintColor);
drawpaint.setStrokeWidth(20);
drawpaint.setStyle(Paint.Style.STROKE);
drawpaint.setStrokeJoin(Paint.Join.ROUND);
drawpaint.setStrokeCap(Paint.Cap.ROUND);
canvaspaint = new Paint(Paint.DITHER_FLAG);
Point p = getScreenSize(context);
int w = p.x;
int h = p.y;
OnSizeChanged(w,h,0,0);
}
protected Point getScreenSize(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return size;
}
protected void OnSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w,h,oldw,oldh);
Log.d("OnSizeChanged: ", "method is called");
canvasBitmap = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
drawcanvas = new Canvas(canvasBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d("onDraw: ", "method is called");
drawcanvas.drawBitmap(canvasBitmap,0,0,canvaspaint);
canvas.drawPath(drawpath, drawpaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
Log.d("onTouchEvent: ", "method is called");
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawpath.moveTo(touchX,touchY);
break;
case MotionEvent.ACTION_MOVE:
drawpath.lineTo(touchX,touchY);
break;
case MotionEvent.ACTION_UP:
drawcanvas.drawPath(drawpath, drawpaint);
drawpath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
}
//private DrawView drawView = new DrawView(); this is the problematic instantiation
}
编辑:我想添加一些新内容以反映给出的答案。
按照Bruce提出的想法,我扩展了DrawingFragment的XML文件。不幸的是,这导致了进一步的崩溃,毫无疑问,我自己的一些天真应该受到指责。任何人都可以就此问题分享一些见解吗?
logcat的:
12-01 15:38:50.116 8045-8045/com.example.chris.drawingtest D/onCreateView:﹕ This ran successfully
12-01 15:38:50.126 8045-8045/com.example.chris.drawingtest D/AndroidRuntime﹕ Shutting down VM
12-01 15:38:50.126 8045-8045/com.example.chris.drawingtest W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x41c9aba8)
12-01 15:38:50.126 8045-8045/com.example.chris.drawingtest E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.chris.drawingtest, PID: 8045
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.chris.drawingtest/com.example.chris.drawingtest.DrawingActivity}: android.view.InflateException: Binary XML file line #11: Error inflating class com.example.chris.drawingtest.DrawingFragment$DrawView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #11: Error inflating class com.example.chris.drawingtest.DrawingFragment$DrawView
at android.view.LayoutInflater.createView(LayoutInflater.java:603)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at com.example.chris.drawingtest.DrawingFragment.onCreateView(DrawingFragment.java:32)
at android.app.Fragment.performCreateView(Fragment.java:1700)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:866)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1040)
at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1142)
at android.app.Activity.onCreateView(Activity.java:4786)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:689)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
at android.app.Activity.setContentView(Activity.java:1929)
at com.example.chris.drawingtest.DrawingActivity.onCreate(DrawingActivity.java:18)
at android.app.Activity.performCreate(Activity.java:5231)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
at java.lang.Class.getConstructorOrMethod(Class.java:472)
at java.lang.Class.getConstructor(Class.java:446)
at android.view.LayoutInflater.createView(LayoutInflater.java:568)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at com.example.chris.drawingtest.DrawingFragment.onCreateView(DrawingFragment.java:32)
at android.app.Fragment.performCreateView(Fragment.java:1700)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:866)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1040)
at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1142)
at android.app.Activity.onCreateView(Activity.java:4786)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:689)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
at android.app.Activity.setContentView(Activity.java:1929)
at com.example.chris.drawingtest.DrawingActivity.onCreate(DrawingActivity.java:18)
at android.app.Activity.performCreate(Activity.java:5231)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
片段XML:
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".com.example.chris.drawingtest.DrawingFragment"
>
<view
xmlns:android="http://schemas.android.com/apk/res/android"
class="com.example.chris.drawingtest.DrawingFragment$DrawView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
答案 0 :(得分:2)
为什么要在名称恰当的View
之外创建自定义onCreateView
?或许试一试:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d("onCreateView: ","This ran successfully");
View v = inflater.inflate(R.layout.fragment_drawing, container, false);
drawView = new DrawView(v.getContext());
//and then add drawView wherever you want it within fragment_drawing
//((ViewGroup)v).addView(drawView); *change this to where you want the view and with the appropriate casting and layout parameters*
return v;
}
答案 1 :(得分:2)
这里有一些问题。
1)您已将View子类作为Fragment的内部类,这意味着每个构造函数都有一个隐含的DrawingFragment参数。这意味着您的View没有Android从XML构造Views所需的标准构造函数。您应该将内部类设置为静态,或者将其放在自己的文件中。
2)你有OnSizeChanged(上限O),它不会覆盖小写版本,然后你调用超级版本。我看到你是从你的构造函数中调用你的版本,但如果Android出于某种原因调整你的视图大小,你就不会听到它。
3)您可能希望跟踪画布的当前大小,因此每次调用onSizeChanged时都可以避免重新创建它。他们可能已经解决了这个问题,但在过去,我已经看到过多次调用此函数,大小相同。
4)您确定要使用画布的屏幕尺寸吗?这将包括您无法实际绘制的区域。最好将你的片段和你的视图作为match_parent的宽度和高度,然后等待Android在onSizeChanged中告诉你你的大小。如果您在片段的布局文件R.layout.fragment_drawing(这是您应该做的)中有DrawView,那么您可以在那里设置match_parent属性。
5)说到属性,当Android从XML中膨胀视图时,它们使用与仅上下文版本不同的构造函数。我会为您的自定义视图推荐以下常用模式:
public DrawView(Context context) {
this(context, null);
}
public DrawView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//TODO your constructor body here
}
修改
回答有关如何实例化自定义视图的问题。听起来你的DrawView占用了你的整个片段,所以我会这样写。但是,你当然也可以像RelativeLayout这样的父视图作为文件的根目录,并使DrawView成为子视图。另一个影响答案的是DrawView是否仍然是片段的内部类。更简单的情况是DrawView是否在自己的文件中。然后你可以这样做:
<com.example.chris.drawingtest.DrawView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />
如果您将DrawView保持为静态内部类,那么您使用&#39; $&#39;分隔符而不是&#39;。但是,&#39; $&#39;是XML的特殊字符,因此您无法在标记中使用它。但是,您可以将类名指定为视图标记的XML属性。像这样:
<view
xmlns:android="http://schemas.android.com/apk/res/android"
class="com.example.chris.drawingtest.DrawingFragment$DrawView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
编辑:
是的,这次崩溃正是我在上面#1和#5中讨论的问题。异常java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
告诉您Android无法找到一个View构造函数,它接受Context和AttributeSet(我展示的3个构造函数中的第2个)。确保您的DrawView类是公共的,静态的,并且包含所有构造函数。
public class DrawingFragment extends Fragment {
public static class DrawView extends View {
... // 3 constructors shown above
编辑:
由于您希望将绘制片段放在另一个片段的顶部并占据屏幕的大部分,我会使用RelativeLayout作为您活动的根视图,然后将您的较小的底部视图放在下面,使用wrap_content高度,然后你上面的绘制片段。您可以使用RelativeLayout参数将片段锚定到活动的顶部和底部。所以layout / draw_activity.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/tools_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
class="com.example.chris.drawingtest.ToolsFragment" />
<fragment
android:id="@+id/draw_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_above="@id/tools_fragment"
class="com.example.chris.drawingtest.DrawingFragment" />
</RelativeLayout>
然后假设您的DrawView填充了您的DrawingFragment,您可以使用我已经显示的XML。