将自定义绘图视图 (canvas) 放入扩展 Fragment 的 class 中

Put a custom Drawing View (canvas) inside a class that extends Fragment

我需要创建一个 "page" 可以用手指画画的地方。我在 Whosebug 上找到了如何做,但我不想创建一个新的 activity,我想像下面这样思考,这可能吗?

扩展框架的class布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">

<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_margin="8dp"
    card_view:cardCornerRadius="4dp">
    <EditText
        android:id="@+id/note_draw_titolo"
        android:layout_width="match_parent"
        android:layout_height="?attr/listPreferredItemHeight"
        android:gravity="center_vertical"
        android:padding="8dp"
        android:hint="Titolo"
        android:textAlignment="center"
        android:textStyle="bold"
        style="@style/Base.TextAppearance.AppCompat.Body2"/>
</android.support.v7.widget.CardView>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp">
    <com.marcocreation.********.DrawingView
        android:id="@+id/drawView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:visibility="visible"
        android:layout_alignParentBottom="true">
    </com.marcocreation.*******.DrawingView>
</RelativeLayout>

绘图视图class:

public class DrawingView extends View {

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

public DrawingView(Context c, AttributeSet attrs, int defStyle) {
    super(c, attrs, defStyle);
    context=c;
    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);
    initPaint();
}

protected void initPaint(){
    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);
}

@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;
}
}

在 customFragment 中,我从以下内容开始:

public class NoteFragment extends Fragment {

private EditText sharedTitolo;
private EditText sharedNota;
private NoteDataSource notesource;
private TextView recordTimeText;
private ImageButton audioSendButton;
private View recordPanel;
private View slideText;
private Context context;
private DrawingView drawView;

public static NoteFragment createInstance(int index, int tipo, Context c) {
    NoteFragment noteFragment = new NoteFragment(c);
    Bundle bundle = new Bundle();
    ...
    return noteFragment;
}

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

}

@SuppressLint("ValidFragment")
public NoteFragment (Context c){
    this.context = c;
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = null;
    Bundle bundle = getArguments();
    switch (bundle.getInt("type")){
        case 1:
            ...
            break;
        case 2:
            view = (View) inflater.inflate(R.layout.note_draw_layout, container, false);
            sharedTitolo = (EditText)view.findViewById(R.id.note_draw_titolo);
            drawView = (DrawingView)view.findViewById(R.id.drawView);
            if(bundle.getInt("index")>0){
                Log.i("nf_indice",""+bundle.getInt("index"));
                sharedTitolo.setText("text");
            }
            else{
                ...
            }
            break;
        case 3:
            ...
            break;
        default:
            break;
    }

    return view;
}
}

但是我得到这个错误:

android.view.InflateException: Binary XML file line #32: Binary XML file line #32: Error inflating class com.marcocreation.******.DrawingView

ps Notefragment 由扩展 appcompactactivity 并创建 FragmentPagerAdapter 的 class 启动,它有一个协调器布局。

完整的错误日志:

07-24 11:03:44.805 29830-29830/com.marcocreation.******* E/AndroidRuntime: FATAL EXCEPTION: main
                                                                          Process: com.marcocreation.*******, PID: 29830
                                                                          android.view.InflateException: Binary XML file line #28: Binary XML file line #28: Error inflating class com.marcocreation.*******.DrawingView
                                                                              at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
                                                                              at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
                                                                              at com.marcocreation.*******.NoteFragment.onCreateView(NoteFragment.java:86)
                                                                              at android.support.v4.app.Fragment.performCreateView(Fragment.java:2074)
                                                                              at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
                                                                              at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1286)
                                                                              at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:758)
                                                                              at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1632)
                                                                              at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:637)
                                                                              at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143)
                                                                              at android.support.v4.view.ViewPager.populate(ViewPager.java:1235)
                                                                              at android.support.v4.view.ViewPager.populate(ViewPager.java:1083)
                                                                              at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1609)
                                                                              at android.view.View.measure(View.java:18794)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                              at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:669)
                                                                              at android.support.design.widget.HeaderScrollingViewBehavior.onMeasureChild(HeaderScrollingViewBehavior.java:89)
                                                                              at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onMeasureChild(AppBarLayout.java:1319)
                                                                              at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:734)
                                                                              at android.view.View.measure(View.java:18794)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                              at android.support.design.widget.CoordinatorLayout.onMeasureChild(CoordinatorLayout.java:669)
                                                                              at android.support.design.widget.CoordinatorLayout.onMeasure(CoordinatorLayout.java:736)
                                                                              at android.view.View.measure(View.java:18794)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                              at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                              at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
                                                                              at android.view.View.measure(View.java:18794)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                              at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
                                                                              at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
                                                                              at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
                                                                              at android.view.View.measure(View.java:18794)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                              at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                              at android.view.View.measure(View.java:18794)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                              at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
                                                                              at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
                                                                              at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
                                                                              at android.view.View.measure(View.java:18794)
                                                                              at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
                                                                              at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
                                                                              at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
                                                                              at android.view.View.measure(View.java:18794)
                                                                              at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2100)
                                                                              at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1216)
                                                                              at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1452)
                                                                              at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
                                                                              at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
                                                                              at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
                                                                              at android.view.Choreographer.doCallbacks(Choreographer.java:670)
                                                                              at android.view.Choreographer.doFrame(Choreographer.java:606)

为了将来参考,这里是有效的解决方案。

在inflation期间调用的View构造函数是View(Context context, AttributeSet attrs),但是在上面的DrawingView中没有提供这样的构造函数。因此 Android 系统无法扩充布局文件,因为它找不到合适的构造函数。

以下 DrawingView 构造函数应该可以解决问题:

// Constructor called during inflation
public DrawingView(Context c, AttributeSet attrs) {
    this(c, attrs, 0);
}

public DrawingView(Context c, AttributeSet attrs, int defStyle) {
    super(c, attrs, defStyle);
    // ...
}