У меня возникли проблемы с сохранением формы рисунков в моем приложении

#java #android #android-studio

#java #Android #android-studio

Вопрос:

Я создаю приложение с несколькими фрагментами, и половина фрагментов имеет пользовательский вид (назовем его canvas), где пользователь может рисовать линии, касаясь и проводя пальцем по холсту.

Мне удалось использовать SharedPreferences для сохранения (пользователю необходимо нажать «Сохранить» в выпадающем меню) и загружать строки, когда пользователь возвращается к фрагменту (после перехода к другому фрагменту или закрытия приложения).

Однако при загрузке исходный рисунок изменяется на группу линий (нумерация равна количеству, необходимому для создания исходного рисунка), исходящих из верхнего левого края холста, почти как солнечные лучи, если это имеет смысл.

Перед сохранением

Перед сохранением

После сохранения и возврата к фрагменту

После сохранения

Я не знаю, почему он загружается таким образом, а не как это исправить, но я считаю, что это как-то связано с методом loadDrawing. Я покажу код ниже (код для фрагментов холста в основном одинаковый, поэтому я покажу код одного фрагмента.

PaintView.java

 import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.EmbossMaskFilter;
import android.graphics.MaskFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;



public class PaintView extends View {

public static int BRUSH_SIZE = 10;
public static final int DEFAULT_COLOR = Color.WHITE;
public static int DEFAULT_BG_COLOR = Color.GRAY;
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
private Paint mPaint;
private static ArrayList<FingerPath> paths = new ArrayList<>();
private int currentColor;
private int backgroundColor = DEFAULT_BG_COLOR;
private int strokeWidth;
private boolean emboss;
private boolean blur;
private MaskFilter mEmboss;
private MaskFilter mBlur;
private Bitmap mBitmap;
public Canvas mCanvas;
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);




public PaintView(Context context) {
    this(context, null);

}

public PaintView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);

    mPaint.setColor(DEFAULT_COLOR);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setXfermode(null);
    mPaint.setAlpha(0xff);

    mEmboss = new EmbossMaskFilter(new float[] {1, 1, 1}, 0.4f, 6, 3.5f);
    mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);

}

public ArrayList getPaths() {
    return paths;

}

public ArrayList setPaths(ArrayList<FingerPath> list) {


    return this.paths = list;
}

public void init(DisplayMetrics metrics) {
    int height = metrics.heightPixels;
    int width = metrics.widthPixels;

    mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);

    loadDrawing(mCanvas);

    currentColor = DEFAULT_COLOR;
    strokeWidth = BRUSH_SIZE;
}

public void normal() {
    emboss = false;
    blur = false;

}



public void clear() {
    backgroundColor = DEFAULT_BG_COLOR;
    paths.clear();
    normal();
    invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.save();
    mCanvas.drawColor(backgroundColor);

        for (FingerPath fp : paths) {

            mPaint.setColor(fp.color);
            mPaint.setStrokeWidth(fp.strokeWidth);
            mPaint.setMaskFilter(null);

            if (fp.emboss)
                mPaint.setMaskFilter(mEmboss);
            else if (fp.blur)
                mPaint.setMaskFilter(mBlur);

            mCanvas.drawPath(fp.path, mPaint);
        }




    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

    canvas.restore();
}

private void touchStart(float x, float y) {
    mPath = new Path();
    FingerPath fp = new FingerPath(currentColor, emboss, blur, strokeWidth, mPath, x, y);

    paths.add(fp);

    mPath.reset();
    mPath.moveTo(x, y);
    mX = x;
    mY = y;
}

private void touchMove(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;
    }
}

private void touchUp() {
    mPath.lineTo(mX, mY);
}

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

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN :
            touchStart(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE :
            touchMove(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP :
            touchUp();
            invalidate();
            break;
    }

    return true;
}


//I believe it is here that problem lies
public void loadDrawing(Canvas canvas) {
    if (mCanvas != null) {


        currentColor = DEFAULT_COLOR;
        strokeWidth = BRUSH_SIZE;
        if (! paths.isEmpty()) {
            canvas.save();
            mCanvas.drawColor(backgroundColor);

            float xTest = 0.0f;
            float yTest = 0.0f;


            for (FingerPath fp : paths) {

                mPaint.setColor(fp.color);
                mPaint.setStrokeWidth(fp.strokeWidth);
                mPaint.setMaskFilter(null);

                if (fp.emboss)
                    mPaint.setMaskFilter(mEmboss);
                else if (fp.blur)
                    mPaint.setMaskFilter(mBlur);

                    //need to figure out how to retain shape upon loading

                if (xTest == 0.0f amp;amp; yTest == 0.0f) {
                    xTest = fp.x;
                    yTest = fp.y;

                    fp.path.quadTo(xTest, yTest, (xTest   fp.x) / 2, (yTest   fp.y) / 2);
                } else {
                    fp.path.quadTo(xTest, yTest, (xTest   fp.x) / 2, (yTest   fp.y) / 2);


                    xTest = fp.x;
                    yTest = fp.y;
                }



            }




            canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

            canvas.restore();
        }

    }
}
}
 

FingerPath.java

 import android.graphics.Path;


public class FingerPath{

public int color;
public boolean emboss;
public boolean blur;
public int strokeWidth;
public Path path;
public float x;
public float y;

public FingerPath(int color, boolean emboss, boolean blur, int strokeWidth, Path path, float x, float 
y) {
    this.color = color;
    this.emboss = emboss;
    this.blur = blur;
    this.strokeWidth = strokeWidth;
    this.path = path;
    this.x = x;
    this.y = y;

}


}
 

LineLHwFragment.java

Фрагмент, содержащий холст

 import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;

public class LineLHwFragment extends Fragment {

private PaintView paintView;
public ArrayList<FingerPath> lineLoad;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable 
Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_line_l_hw, container, false);

        return v;

}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    paintView = view.findViewById(R.id.lineLPaintView);
    loadData();
    DisplayMetrics metrics = new DisplayMetrics();
    getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
    paintView.init(metrics);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.main, menu);
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.normal:
            paintView.normal();
            saveData();
            return true;

        case R.id.clear:
            paintView.clear();
            return true;
    }

    return super.onOptionsItemSelected(item);
}

private void saveData() {
    SharedPreferences sharedPreferences = this.getActivity().getSharedPreferences("line test 1", 
Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPreferences.edit();
    Gson gson = new Gson();
    String json = gson.toJson(paintView.getPaths());
    editor.putString("line test", json);
    editor.apply();
    Toast.makeText(this.getActivity(), "Data saved", Toast.LENGTH_SHORT).show();
}

private void loadData() {
    SharedPreferences sharedPreferences = this.getActivity().getSharedPreferences("line test 1", 
Context.MODE_PRIVATE);
    Gson gson = new Gson();
    String json = sharedPreferences.getString("line test", null);
    Type type = new TypeToken<ArrayList<FingerPath>>() {}.getType();

    lineLoad = gson.fromJson(json, type);
    if (lineLoad != null) {
        paintView.setPaths(lineLoad);
        Toast.makeText(this.getActivity(), "Data loaded", Toast.LENGTH_SHORT).show();
    }
}


}