代码之家  ›  专栏  ›  技术社区  ›  Nitesh

Android应用程序中的数字签名清除问题

  •  2
  • Nitesh  · 技术社区  · 10 年前

    我正在使用自定义视图在android应用程序中实现数字签名功能。
    我希望用户能够在不关闭对话框或重新创建活动的情况下清除并重试新签名。当我清除时,它成功地清除了签名,但不允许绘制新签名,并与先前绘制的签名一起绘制了一些黑色覆盖。

    这是绘制数字签名的类。
    签名.java

    import android.content.Context;  
    import android.graphics.Bitmap;  
    import android.graphics.Canvas;  
    import android.graphics.Color;  
    import android.graphics.Paint;  
    import android.graphics.Path;  
    import android.graphics.PorterDuff;  
    import android.provider.MediaStore;  
    import android.util.AttributeSet;  
    import android.util.Log;  
    import android.view.MotionEvent;  
    import android.view.View;  
    import java.io.File;  
    import java.io.FileOutputStream;  
    
    public class Signature extends View  
    {  
        public static final float STROCK_WIDTH = 5f;  
        public static final float HALF_STROKE_WIDTH = STROCK_WIDTH / 2;  
        private Paint paint = new Paint();  
        View mContent;  
        File mPath1;  
        private Paint mPaint;  
        private Bitmap mBitmap;  
        private Canvas mCanvas;  
        private Path mPath;  
        private Paint mBitmapPaint;  
        boolean clear = false;    
    
        public Signature(Context context)
        {
            super(context);
        }
    
        public Signature(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            paint.setAntiAlias(true);
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeWidth(STROCK_WIDTH);
        }
    
        public Signature(Context context, AttributeSet attrs, View view, File pathToSave)
        {
            this(context, attrs);
            mContent = view;
            mPath1 = pathToSave;
            mPath = new Path();
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);
            setPaint();
        }
    
        public void setPaint()
        {
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(0xFFFF0000);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(12);
        }
    
        public String save(View v)
        {
            String imagePath = null;
            Log.v("TAG", "Width :" + v.getWidth());
            Log.v("TAG", "Height :" + v.getHeight());
            if (mBitmap == null)
            {
                mBitmap = Bitmap.createBitmap(mContent.getWidth(), mContent.getHeight(), Bitmap.Config.RGB_565);
            }
            mBitmap = v.getDrawingCache();
            try
            {
                FileOutputStream mFileOutStream = new FileOutputStream(mPath1);
                mBitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream);
                mFileOutStream.flush();
                mFileOutStream.close();
                imagePath = MediaStore.Images.Media.insertImage(getContext().getContentResolver(), mBitmap, "title", null);
                Log.v("log_tag", "url: " + imagePath + "::we are saving at :" + mPath1);
            }
            catch (Exception e)
            {
                Log.v("log_tag", e.toString());
            }
            return imagePath;
        }
    
        public void clear()
        {
            mPath.reset();  
            mPaint.reset();  
            clear = true;  
            mPath1.delete();  
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);  
            postInvalidate();  
        }  
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh)
        {
            super.onSizeChanged(w, h, oldw, oldh);
            try
            {
                mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
                mCanvas = new Canvas(mBitmap);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas)
        {
            if (clear)
            {
                clear = false;
            }
            else
            {
                canvas.drawColor(0xFFFFFFFF);
                canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
                canvas.drawPath(mPath, mPaint);
            }
        }
    
        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;
            }
        }
    
        private void touch_up()
        {
            mPath.lineTo(mX, mY);
            // 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;
        }  
    }  
    

    使用上述课程的活动
    主要活动.java

    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.app.Dialog;
    import android.content.ContextWrapper;
    import android.graphics.Bitmap;
    import android.graphics.Color;
    import android.graphics.drawable.BitmapDrawable;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Environment;
    import android.provider.MediaStore;
    import android.support.annotation.Nullable;
    import android.support.v7.app.ActionBarActivity;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Base64;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.Window;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.Toast;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    import java.util.Calendar;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        Button btnOpen;
        String imagePath = null,str_signature = "";
        ImageView iv_sign;
        public static String tempDir;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            try {
                btnOpen= (Button) findViewById(R.id.btnOpen);
                btnOpen.setOnClickListener(this);
    
                iv_sign= (ImageView) findViewById(R.id.ivSign);
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_main, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
    
            //noinspection SimplifiableIfStatement
            if (id == R.id.action_settings) {
                return true;
            }
    
            return super.onOptionsItemSelected(item);
        }
    
        @Override
        public void onClick(View v) {
    
            if(v==btnOpen)
            {
                SignatureFragment dialog = new SignatureFragment(onImageClicked);
                dialog.show(MainActivity.this.getSupportFragmentManager(), "NoticeDialogFragment");
            }
        }
    
        ImageSaved onImageClicked = new ImageSaved() {
            @Override
            public void onImageSaved(String path) {
                imagePath = path;
                Uri uri = Uri.parse(imagePath);
                Log.d("TAG", "We got image path :" + imagePath);
                try {
                    Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
                    iv_sign.setImageBitmap(bitmap);
    
                    ImageView img = iv_sign;
                    BitmapDrawable mBitmapDrawable = (BitmapDrawable) img.getDrawable();
                    Bitmap mBitmap = mBitmapDrawable.getBitmap();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
                    byte[] byteArrayImage = baos.toByteArray();
                    str_signature = Base64.encodeToString(byteArrayImage,
                            Base64.DEFAULT);
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
    
        public static class SignatureFragment extends android.support.v4.app.DialogFragment implements View.OnClickListener {
            LinearLayout ll_signature_view;
            Signature signature;
            Button btn_done, btn_clear,btnCancel;
            String EXTERNAL_DIR = "TTD";
            ImageSaved saveListner;
            File mypath;
    
            @SuppressLint("ValidFragment")
            public SignatureFragment(ImageSaved onImageClicked) {
                saveListner = onImageClicked;
            }
    
            @Override
            public void onAttach(Activity activity) {
                super.onAttach(activity);
            }
    
            @Override
            public void onDetach() {
                saveListner = null;
                super.onDetach();
            }
    
            public SignatureFragment() {
            }
    
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setStyle(android.support.v4.app.DialogFragment.STYLE_NO_FRAME, R.style.Base_Theme_AppCompat_Light_Dialog);
            }
    
            @Override
            public Dialog onCreateDialog(Bundle savedInstanceState) {
                Dialog dialog = super.onCreateDialog(savedInstanceState);
                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                return dialog;
            }
    
            @Nullable
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
                View rootView = inflater.inflate(R.layout.signature_view, container, false);
                try
                {
                    ll_signature_view = (LinearLayout) rootView.findViewById(R.id.ll_signature_view);
                    btn_done = (Button) rootView.findViewById(R.id.btn_done);
                    btn_clear = (Button) rootView.findViewById(R.id.btn_clear);
                    btnCancel = (Button) rootView.findViewById(R.id.btn_cancel);
                    tempDir = Environment.getExternalStorageDirectory() + "/" + EXTERNAL_DIR + "/";
                    File directory = getActivity().getCacheDir();
                    prepareDirectory();
                    String uniqueId = getTodaysDate() + "_" + getCurrentTime() + "_" + Math.random();
                    String current = uniqueId + ".png";
                    mypath = new File(directory, current);
    
                    signature = new Signature(getActivity(), null, ll_signature_view, mypath);
                    ll_signature_view.setBackgroundColor(Color.WHITE);
                    ll_signature_view.addView(signature, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
                    btn_done.setOnClickListener(this);
                    btn_clear.setOnClickListener(this);
                    btnCancel.setOnClickListener(this);
                }
                catch(Exception ex)
                {
                    ex.printStackTrace();
                }
    
                return rootView;
            }
    
            @Override
            public void onClick(View v) {
                if (v == btn_done) {
                    ll_signature_view.setDrawingCacheEnabled(true);
                    String imagePath = signature.save(ll_signature_view);
                    if (saveListner != null) {
                        saveListner.onImageSaved(imagePath);
                    }
                    dismiss();
    
                }
                if (v == btnCancel) {
                    dismiss();
                }
                if(v==btn_clear)
                {
                    signature.clear();
                }
            }
    
            private boolean prepareDirectory() {
                try {
                    if (makedirs()) {
                        return true;
                    } else {
                        return false;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Toast.makeText(getActivity(), "Could not initiate File System.. Is Sdcard mounted properly?", Toast.LENGTH_SHORT).show();
                    return false;
                }
            }
    
            private boolean makedirs() {
                File tempdir = new File(tempDir);
                if (!tempdir.exists()) {
                    tempdir.mkdirs();
                }
    
                if (tempdir.isDirectory()) {
                    File[] files = tempdir.listFiles();
                    for (File file : files) {
                        if (!file.delete()) {
                            System.out.println("Failed to delete " + file);
                        }
                    }
                }
                return (tempdir.isDirectory());
            }
    
            private String getTodaysDate() {
    
                final Calendar c = Calendar.getInstance();
                int todaysDate = (c.get(Calendar.YEAR) * 10000) +
                        ((c.get(Calendar.MONTH) + 1) * 100) +
                        (c.get(Calendar.DAY_OF_MONTH));
                Log.w("DATE:", String.valueOf(todaysDate));
                return (String.valueOf(todaysDate));
    
            }
    
            private String getCurrentTime() {
    
                final Calendar c = Calendar.getInstance();
                int currentTime = (c.get(Calendar.HOUR_OF_DAY) * 10000) +
                        (c.get(Calendar.MINUTE) * 100) +
                        (c.get(Calendar.SECOND));
                Log.w("TIME:", String.valueOf(currentTime));
                return (String.valueOf(currentTime));
            }
        }
    
    }
    

    布局文件
    签名_视图.xml

    <?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="match_parent"
        android:orientation="vertical"
        android:layout_margin="8dp">
    
        <LinearLayout
            android:id="@+id/ll_signature_view"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@drawable/edittext_border_white"
            android:orientation="horizontal">
    
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginTop="8dp">
    
            <Button
                android:id="@+id/btn_done"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="DONE" />
    
            <Button
                android:id="@+id/btn_clear"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="CLEAR" />
    
            <Button
                android:id="@+id/btn_cancel"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="CANCEL" />
    
        </LinearLayout>
    </LinearLayout>  
    

    活动_最小.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="@dimen/activity_vertical_margin"
        tools:context=".MainActivity"
        android:background="@android:color/white">
    
        <TextView
            android:id="@+id/tvWelcome"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/Welcome" />
    
        <Button
            android:layout_marginTop="10dp"
            android:id="@+id/btnOpen"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/Open"
            android:gravity="center"
            android:layout_below="@+id/tvWelcome"/>
    
        <ImageView
            android:id="@+id/ivSign"
            android:layout_marginTop="10dp"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            android:layout_below="@+id/btnOpen"
            />
    
    </RelativeLayout> 
    
    3 回复  |  直到 8 年前
        1
  •  0
  •   Bhavesh Desai    10 年前
    mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
    

    试试这个

    canvas.drawColor(0xFFFFFFFF);
    

    并设置图层类型

    mCanvas.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    
        2
  •  0
  •   Nitesh    10 年前

    在这里回答我自己的问题..:)

    按照我上面的要求,我关闭并重新打开了一个对话框,解决了我的问题。

    在MainActivity.java中

     if(v==btn_clear)
     {
          dismiss();
          SignatureFragment dialog = new SignatureFragment(saveListner);
          dialog.show(getActivity().getSupportFragmentManager(), "NoticeDialogFragment");
     } 
    
        3
  •  0
  •   snehal    7 年前

    使用库: 'com.github.gacace:签名板:1.2.1'

    在这里,您可以使用SignaturePad类的clear()方法。清除所有输入的数据将被删除,您可以添加新内容。