简体   繁体   English

签名视图无法在Android 8 +设备上运行

[英]Signature view not working on Android 8 + devices

I am working on an application which captures an applicant's signature and saves it to the phone memory. 我正在开发一个应用程序,它捕获申请人的签名并将其保存到手机内存中。 The class used for the signature view is given below 用于签名视图的类如下所示

public class SignatureView extends View {

      private static final float STROKE_WIDTH = 5f;

      /** Need to track this so the dirty region can accommodate the stroke. **/
      private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;

      private Paint paint = new Paint();
      private Path path = new Path();

      /**
       * Optimizes painting by invalidating the smallest possible area.
       */
      private float lastTouchX;
      private float lastTouchY;
      private final RectF dirtyRect = new RectF();

      public SignatureView(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(STROKE_WIDTH);
      }

      /**
       * Erases the signature.
       */
      public void clear() {
        path.reset();

        // Repaints the entire view.
        invalidate();
      }

      @Override
      protected void onDraw(Canvas canvas) {
          canvas.drawARGB(255, 233, 255, 255);
        canvas.drawPath(path, paint);
      }

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

        switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
            path.moveTo(eventX, eventY);
            lastTouchX = eventX;
            lastTouchY = eventY;
            // There is no end point yet, so don't waste cycles invalidating.
            return true;

          case MotionEvent.ACTION_MOVE:
          case MotionEvent.ACTION_UP:
            // Start tracking the dirty region.
            resetDirtyRect(eventX, eventY);

            // When the hardware tracks events faster than they are delivered, the
            // event will contain a history of those skipped points.
            int historySize = event.getHistorySize();
            for (int i = 0; i < historySize; i++) {
              float historicalX = event.getHistoricalX(i);
              float historicalY = event.getHistoricalY(i);
              expandDirtyRect(historicalX, historicalY);
              path.lineTo(historicalX, historicalY);
            }

            // After replaying history, connect the line to the touch point.
            path.lineTo(eventX, eventY);
            break;

          default:
            //debug("Ignored touch event: " + event.toString());
            return false;
        }

        // Include half the stroke width to avoid clipping.
        invalidate(
            (int) (dirtyRect.left - HALF_STROKE_WIDTH),
            (int) (dirtyRect.top - HALF_STROKE_WIDTH),
            (int) (dirtyRect.right + HALF_STROKE_WIDTH),
            (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));

        lastTouchX = eventX;
        lastTouchY = eventY;

        return true;
      }

      /**
       * Called when replaying history to ensure the dirty region includes all
       * points.
       */
      private void expandDirtyRect(float historicalX, float historicalY) {
        if (historicalX < dirtyRect.left) {
          dirtyRect.left = historicalX;
        } else if (historicalX > dirtyRect.right) {
          dirtyRect.right = historicalX;
        }
        if (historicalY < dirtyRect.top) {
          dirtyRect.top = historicalY;
        } else if (historicalY > dirtyRect.bottom) {
          dirtyRect.bottom = historicalY;
        }
      }

      /**
       * Resets the dirty region when the motion event occurs.
       */
      private void resetDirtyRect(float eventX, float eventY) {

        // The lastTouchX and lastTouchY were set when the ACTION_DOWN
        // motion event occurred.
        dirtyRect.left = Math.min(lastTouchX, eventX);
        dirtyRect.right = Math.max(lastTouchX, eventX);
        dirtyRect.top = Math.min(lastTouchY, eventY);
        dirtyRect.bottom = Math.max(lastTouchY, eventY);
      }

      // get drawn image as bitmap
      public Bitmap getBitmap() {
        this.setDrawingCacheEnabled(true);
        this.buildDrawingCache();
        Bitmap bmp = Bitmap.createBitmap(this.getDrawingCache());
        this.setDrawingCacheEnabled(false);

        return bmp;
      }


      public boolean isDrawn(){
        return ! path.isEmpty();
      }

}

This class returns the signature bitmap.This view works fine for devices with Android 8.0 and below, but its not working for Android 8.0 plus devices. 此类返回签名位图。此视图适用于Android 8.0及更低版本的设备,但不适用于Android 8.0 plus设备。 For Devices above Android 8.0, the method getBitmap() returns a bitmap of the signature, but for Devices above Android 8.0, it returns empty. 对于Android 8.0以上的设备,方法getBitmap()返回签名的位图,但对于Android 8.0以上的设备,它返回空。

Another Solution I tried which did not work either 我试过的另一个解决方案也没用

 public class SignatureViewType3 extends View {

    private Bitmap _Bitmap;
    private Canvas _Canvas;
    private Path _Path;
    private Paint _BitmapPaint;
    private Paint _paint;
    private float _mX;
    private float _mY;
    private float TouchTolerance = 4;
    private float LineThickness = 4;
    private boolean signatureAdded;

    public SignatureViewType3(Context context, AttributeSet attr) {
        super(context, attr);
        _Path = new Path();
        _BitmapPaint = new Paint(Paint.DITHER_FLAG);
        _paint = new Paint();
        _paint.setAntiAlias(true);
        _paint.setDither(true);
        _paint.setColor(Color.argb(255, 0, 0, 0));
        _paint.setStyle(Paint.Style.STROKE);
        _paint.setStrokeJoin(Paint.Join.ROUND);
        _paint.setStrokeCap(Paint.Cap.ROUND);
        _paint.setStrokeWidth(LineThickness);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        _Bitmap = Bitmap.createBitmap(w, (h > 0 ? h : ((View) this.getParent()).getHeight()), Bitmap.Config.ARGB_8888);
        _Canvas = new Canvas(_Bitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        getParent().requestDisallowInterceptTouchEvent(true);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(_Bitmap, 0, 0, _BitmapPaint);
        canvas.drawPath(_Path, _paint);
    }

    private void TouchStart(float x, float y) {
        _Path.reset();
        _Path.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 >= TouchTolerance || dy >= TouchTolerance) {
            _Path.quadTo(_mX, _mY, (x + _mX) / 2, (y + _mY) / 2);
            _mX = x;
            _mY = y;
        }
    }

    private void TouchUp() {
        if (!_Path.isEmpty()) {
            _Path.lineTo(_mX, _mY);
            _Canvas.drawPath(_Path, _paint);
        } else {
            _Canvas.drawPoint(_mX, _mY, _paint);
        }
        signatureAdded = true;

        _Path.reset();
    }

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

        switch (e.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;
    }

    public void clear() {
        _Canvas.drawColor(Color.WHITE);
        invalidate();
    }

    public byte[] getBytes() {
        Bitmap b = getBitmap();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        b.compress(Bitmap.CompressFormat.PNG, 100, baos);
        if(signatureAdded)
            return baos.toByteArray();
        else
            return null;
    }

    public Bitmap getBitmap() {
        View v = (View) this.getParent();
        Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);
        v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
        v.draw(c);

        return b;
    }

    public boolean isDrawn(){
//      return ! _Path.isEmpty();
        return true;
    }
}

getDrawingCache() is deprecated in Android API 28, so you should use Canvas like in this answer of Ashvin solanki getDrawingCache()被弃用的Android API 28,所以你应该使用Canvas在像这样的答案Ashvin索兰奇

 RelativeLayout view = (RelativeLayout)findViewById(R.id.relativelayout); Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Drawable bgDrawable = view.getBackground(); if (bgDrawable != null) { bgDrawable.draw(canvas); } else { canvas.drawColor(Color.WHITE); } view.draw(canvas); 

or PixelCopy like in that article of Shivesh Karan Mehta : PixelCopy喜欢Shivesh卡兰·梅塔

 // for api level 28 fun getScreenShotFromView(view: View, activity: Activity, callback: (Bitmap) -> Unit) { activity.window?.let { window -> val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888) val locationOfViewInWindow = IntArray(2) view.getLocationInWindow(locationOfViewInWindow) try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { PixelCopy.request( window, Rect( locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height ), bitmap, { copyResult -> if (copyResult == PixelCopy.SUCCESS) { callback(bitmap) } else { } // possible to handle other result codes ... }, Handler() ) } } catch (e: IllegalArgumentException) { // PixelCopy may throw IllegalArgumentException, make sure to handle it e.printStackTrace() } } } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM