florent37 / ShapeOfView

Give a custom shape to any android view, Material Design 2 ready
Apache License 2.0
3.12k stars 400 forks source link

Can I use SurfaceView inside ShapeOfView #47

Open ZDZN opened 5 years ago

ZDZN commented 5 years ago

I wanted to show camera preview in a circle view, so I tried to put a SurfaceView inside CircleView. But the SurfaceView seemed to be covered by CircleView and showed nothing. If I change the CircleView to FrameLayout, SurfaceView can show camera preview in a rect. Can you give me some advice to solve this ?Thank you.

<com.github.florent37.shapeofview.shapes.CircleView
        android:layout_width="200dp"
        android:layout_height="200dp">
        <SurfaceView
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
</com.github.florent37.shapeofview.shapes.CircleView>
ZDZN commented 5 years ago

I modified your code to achieve my effect as the code below, but I still hope your library can support using SurfaceView inside ShapeOfView.

public class MaskLayout extends FrameLayout {

    private Paint mTransparentPaint;
    private Paint mDrawPaint;
    private MaskManager mMaskManager;
    private boolean mRequireUpdate;

    public MaskLayout(@NonNull Context context) {
        this(context, null, 0);
    }

    public MaskLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MaskLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mTransparentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

        mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mDrawPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mDrawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mDrawPaint.setStrokeWidth(1);

        mRequireUpdate = true;
        mMaskManager = new MaskManager();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            requireUpdate();
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if(null == mMaskManager) {
            super.dispatchDraw(canvas);
            return;
        }
        int width = getWidth() - getPaddingLeft() - getPaddingRight();
        int height = getHeight() - getPaddingTop() - getPaddingBottom();
        if(mRequireUpdate) {
            mMaskManager.setupMask(width, height);
            //this needs to be fixed for 25.4.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && ViewCompat.getElevation(this) > 0f) {
                try {
                    setOutlineProvider(getOutlineProvider());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            postInvalidate();
            mRequireUpdate = false;
        }

        canvas.drawPath(mMaskManager.getMask(), mTransparentPaint);
        canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
        super.dispatchDraw(canvas);
        canvas.drawPath(mMaskManager.getMask(), mDrawPaint);
        canvas.restore();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public ViewOutlineProvider getOutlineProvider() {
        return new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                if (mMaskManager != null && !isInEditMode()) {
                    final Path shadowConvexPath = mMaskManager.getShadow();
                    if (shadowConvexPath != null) {
                        try {
                            outline.setConvexPath(shadowConvexPath);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        };
    }

    public void setMakCreator(MaskManager.MaskCreator creator) {
        mMaskManager.setMaskCreator(creator);
        requireUpdate();
    }

    private void requireUpdate() {
        mRequireUpdate = true;
        postInvalidate();
    }
}
florent37 commented 5 years ago

what did you change to make it work ? So I can add it inside ShapeOfView

Le lun. 28 janv. 2019 à 03:24, ZDZN notifications@github.com a écrit :

I modified your code to achieve my effect as the code below, but I still hope your library can support using SurfaceView inside ShapeOfView.

public class MaskLayout extends FrameLayout {

private Paint mTransparentPaint;
private Paint mDrawPaint;
private MaskManager mMaskManager;
private boolean mRequireUpdate;

public MaskLayout(@NonNull Context context) {
    this(context, null, 0);
}

public MaskLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
}

public MaskLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    mTransparentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

    mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mDrawPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    mDrawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    mDrawPaint.setStrokeWidth(1);

    mRequireUpdate = true;
    mMaskManager = new MaskManager();
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    if (changed) {
        requireUpdate();
    }
}

@Override
protected void dispatchDraw(Canvas canvas) {
    if(null == mMaskManager) {
        super.dispatchDraw(canvas);
        return;
    }
    int width = getWidth() - getPaddingLeft() - getPaddingRight();
    int height = getHeight() - getPaddingTop() - getPaddingBottom();
    if(mRequireUpdate) {
        mMaskManager.setupMask(width, height);
        //this needs to be fixed for 25.4.0
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && ViewCompat.getElevation(this) > 0f) {
            try {
                setOutlineProvider(getOutlineProvider());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        postInvalidate();
        mRequireUpdate = false;
    }

    canvas.drawPath(mMaskManager.getMask(), mTransparentPaint);
    canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
    super.dispatchDraw(canvas);
    canvas.drawPath(mMaskManager.getMask(), mDrawPaint);
    canvas.restore();
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public ViewOutlineProvider getOutlineProvider() {
    return new ViewOutlineProvider() {
        @Override
        public void getOutline(View view, Outline outline) {
            if (mMaskManager != null && !isInEditMode()) {
                final Path shadowConvexPath = mMaskManager.getShadow();
                if (shadowConvexPath != null) {
                    try {
                        outline.setConvexPath(shadowConvexPath);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    };
}

public void setMakCreator(MaskManager.MaskCreator creator) {
    mMaskManager.setMaskCreator(creator);
    requireUpdate();
}

private void requireUpdate() {
    mRequireUpdate = true;
    postInvalidate();
}

}

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/florent37/ShapeOfView/issues/47#issuecomment-457980222, or mute the thread https://github.com/notifications/unsubscribe-auth/AFfQXAITQEw5sVw30t_vIVywK8rykNQaks5vHl9HgaJpZM4aQUV0 .

ZDZN commented 5 years ago

@florent37 I draw a hole for SurfaceView by using PorterDuff.Mode.CLEAR before I call super.dispatchDraw(canvas). I am not familiar with the effect about changing layer type, so I use saveLayer instead of setLayerType. ShapeOfView use different parameters for setLayerType and drawPath in order to be compatible with different version, but my codes only tested in my phone and may not be compatible with your view.

The main change as the code below:

canvas.drawPath(mMaskManager.getMask(), mTransparentPaint); // draw a hole for SurfaceView
canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG); // save a layer to draw child
super.dispatchDraw(canvas); // draw child
canvas.drawPath(mMaskManager.getMask(), mDrawPaint); // clip shape
canvas.restore();