6

notch image

This question has already been asked and an answer has been accepted here but the accepted answer is not what I am looking for. I want to use a customview in which the notch takes the width + some margin of the view which it is going over, like the pay icon in the above image. While looking into the bottomappbar which houses a fab like this I saw a class called the edge treatment class I guess that can be used as well. I am not posting my customview code rightnow as all I could draw is a rectangle.

aminography
  • 21,986
  • 13
  • 70
  • 74
Pemba Tamang
  • 1,235
  • 16
  • 38

2 Answers2

8

You need to draw the curves using Cubic Bézier Curve. A good article to know how to draw such curves is written by Bartosz Ciechanowski, here.

enter image description here

I have developed a View to draw a shape like google pay which inherits from FrameLayout. The source code is available on its github repository (but not documented yet!). However, add the following lines to your app level build.gradle file:

repositories {
    jcenter()
}

dependencies {
    implementation 'com.aminography:beziercurvebulgelayout:1.0.2'
}

Then you can use it in xml layout files as following:

<com.aminography.view.BezierCurveBulgeLayout
    android:id="@+id/bulgeLayout"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    app:bulgeType="bulge"
    app:bulgeColor="@color/colorPrimary"
    app:curveWidth="32dp"
    app:flatWidth="56dp"
    app:flatHeight="24dp">

    <android.support.v7.widget.AppCompatImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:src="@android:drawable/ic_menu_compass"/>

</com.aminography.view.BezierCurveBulgeLayout>

enter image description here .

Its shape and color is customizable to achieve the target shape by changing below attributes:

enter image description here

aminography
  • 21,986
  • 13
  • 70
  • 74
  • sorry @aminography I mistakenly accepted another answer. Please wait a while I have a old question I will give you your rep there as soon as I can raise the bounty. Right now I seem to be on some type of cooldown time. Btw do you make tutorials??? – Pemba Tamang Dec 21 '18 at 09:03
  • hey @aminography – Pemba Tamang Dec 26 '18 at 07:17
  • would you like to take that bounty on a different question just give a reasonable answer https://stackoverflow.com/questions/49584981/weakhandler-memory-leak – Pemba Tamang Dec 26 '18 at 07:34
0

In addition of above answer of @aminography

If anyone looking for answer in java here is the working code in JAVA

BezierCurveBulgeLayout

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.widget.FrameLayout;

public class BezierCurveBulgeLayout extends FrameLayout {

    AttributeSet attrs;
    int defStyleAttr = 0;
    int defStyleRes = 0;

    private int curveWidth;
    private int flatWidth;
    private int flatHeight;
    private int bulgeColor;
    private BulgeType bulgeType;


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

    private Point startCurveStartPoint = new Point();
    private Point startCurveEndPoint = new Point();
    private Point startCurveFirstControlPoint = new Point();
    private Point startCurveSecondControlPoint = new Point();

    private Point endCurveStartPoint = new Point();
    private Point endCurveEndPoint = new Point();
    private Point endCurveFirstControlPoint = new Point();
    private Point endCurveSecondControlPoint = new Point();

    public BezierCurveBulgeLayout(@NonNull Context context) {
        super(context);
        init();
    }


    public BezierCurveBulgeLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.attrs = attrs;

        init();
    }

    public BezierCurveBulgeLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.attrs = attrs;
        this.defStyleAttr = defStyleAttr;
        init();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public BezierCurveBulgeLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        this.attrs = attrs;
        this.defStyleAttr = defStyleAttr;
        this.defStyleRes = defStyleRes;
        init();
    }


    private void init() {

        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.BezierCurveBulgeLayout, defStyleAttr, defStyleRes);

        curveWidth = a.getDimensionPixelSize(R.styleable.BezierCurveBulgeLayout_curveWidth, 0);
        flatWidth = a.getDimensionPixelSize(R.styleable.BezierCurveBulgeLayout_flatWidth, 0);
        flatHeight = a.getDimensionPixelSize(R.styleable.BezierCurveBulgeLayout_flatHeight, 0);
        bulgeType = BulgeType.values()[a.getInt(R.styleable.BezierCurveBulgeLayout_bulgeType, BulgeType.BULGE.ordinal())];
        bulgeColor = a.getColor(R.styleable.BezierCurveBulgeLayout_bulgeColor, Color.WHITE);

        a.recycle();

        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setColor(bulgeColor);
        setBackgroundColor(Color.TRANSPARENT);
    }

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

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        int viewWidth = getWidth();
        int viewHeight = getHeight();

        int baseY = 0;
        int flatY = 0;

        if (bulgeType == BulgeType.BULGE) baseY = flatHeight;
        else flatY = flatHeight;


        startCurveStartPoint.set(viewWidth / 2 - flatWidth / 2 - curveWidth * 7 / 6, baseY);
        startCurveEndPoint.set(viewWidth / 2 - flatWidth / 2, flatY);


        endCurveStartPoint.set(viewWidth / 2 + flatWidth / 2, flatY);
        endCurveEndPoint.set(viewWidth / 2 + flatWidth / 2 + curveWidth * 7 / 6, baseY);


        startCurveFirstControlPoint.set(startCurveStartPoint.x + curveWidth * 5 / 8, startCurveStartPoint.y);
        startCurveSecondControlPoint.set(startCurveEndPoint.x - curveWidth / 2, startCurveEndPoint.y);

        endCurveFirstControlPoint.set(endCurveStartPoint.x + curveWidth / 2, endCurveStartPoint.y);
        endCurveSecondControlPoint.set(endCurveEndPoint.x - curveWidth * 5 / 8, endCurveEndPoint.y);

        path.reset();
        path.moveTo(0f, baseY);
        path.lineTo((float) startCurveStartPoint.x, (float) startCurveStartPoint.y);

        path.cubicTo(
                (float) startCurveFirstControlPoint.x, (float) startCurveFirstControlPoint.y,
                (float) startCurveSecondControlPoint.x, (float) startCurveSecondControlPoint.y,
                (float) startCurveEndPoint.x, (float) startCurveEndPoint.y
        );

        path.lineTo((float) endCurveStartPoint.x, (float) endCurveStartPoint.y);

        path.cubicTo(
                (float) endCurveFirstControlPoint.x, (float) endCurveFirstControlPoint.y,
                (float) endCurveSecondControlPoint.x, (float) endCurveSecondControlPoint.y,
                (float) endCurveEndPoint.x, (float) endCurveEndPoint.y
        );

        path.lineTo((float) viewWidth, (float) baseY);
        path.lineTo((float) viewWidth, (float) viewHeight);
        path.lineTo(0f, (float) viewHeight);
        path.close();
    }

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

    public enum BulgeType {
        BULGE,
        NOTCH
    }

}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="BezierCurveBulgeLayout">
        <attr name="curveWidth" format="dimension"/>
        <attr name="flatWidth" format="dimension"/>
        <attr name="flatHeight" format="dimension"/>
        <attr name="bulgeColor" format="color"/>
        <attr name="bulgeType" format="enum">
            <enum name="bulge" value="0"/>
            <enum name="notch" value="1"/>
        </attr>
    </declare-styleable>
</resources>

Now use like this in your layout.xml file

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00fff7"
    android:gravity="center"
    tools:context=".MainActivity">

    <neel.com.demo.BezierCurveBulgeLayout
        android:id="@+id/bulgeLayout"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        app:bulgeColor="@color/colorPrimary"
        app:bulgeType="bulge"
        app:curveWidth="32dp"
        app:flatHeight="20dp"
        app:flatWidth="80dp">

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center"
            android:src="@drawable/ic_fav" />

    </neel.com.demo.BezierCurveBulgeLayout>

</LinearLayout>

OUTPUT

enter image description here

AskNilesh
  • 67,701
  • 16
  • 123
  • 163
  • 1
    Thanks dude :) I wrote the library in kotlin, may someone need it in java. – aminography Dec 21 '18 at 07:31
  • 1
    @aminography yeh thanks and all credit goes to you that;s why i added `In addition of above answer of @aminography` hope it helps to others – AskNilesh Dec 21 '18 at 07:33