Skip to content

Instantly share code, notes, and snippets.

@karanatwal

karanatwal/.java Secret

Last active August 9, 2022 11:39
Show Gist options
  • Save karanatwal/78085a546a309209a40892a595b4a476 to your computer and use it in GitHub Desktop.
Save karanatwal/78085a546a309209a40892a595b4a476 to your computer and use it in GitHub Desktop.
Instagram like Editext by Karan Atwal
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.Layout;
import android.util.AttributeSet;
import android.view.KeyEvent;
/**
* Created by Karandeep Atwal on 04/01/18.
+919646874950
Chandigarh, India
karanatwal00@gmail.com
*/
public class InstaEditext extends android.support.v7.widget.AppCompatEditText {
Paint paint ;
Path path = new Path();
int CORNER = 36;
int OFFSET = CORNER/2;
int SIDE_OFFSET = 15;
private onKeyBoardDown onKeyBoardDown;
private int bgColor = Color.parseColor("#FC812B");
private float textSize = 60f;
public InstaEditext(Context context) {
this(context,null);
}
public InstaEditext(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public InstaEditext(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = getPaint();
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
if (path!=null)path.reset();
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (onKeyBoardDown!=null){
onKeyBoardDown.onBackPress();
}
}
return false;
}
public void setOnKeyboardDownListener(onKeyBoardDown onKeyboardDown){
this.onKeyBoardDown=onKeyboardDown;
}
public void setSideOffset(boolean sideOffsetNeeded) {
if (sideOffsetNeeded){
SIDE_OFFSET=15;
}else {
SIDE_OFFSET=0;
}
}
public interface onKeyBoardDown{
void onBackPress();
}
public void changeBgColor(int color){
bgColor = color;
if (paint!=null)paint.setColor(color);
invalidate();
}
public void setTextSize(float textSize){
this.textSize = textSize;
}
public float getTextSize(){
return textSize;
}
@Override
protected void onDraw(Canvas canvas) {
Layout layout = getLayout();
paint.setTextSize(textSize);
paint.setColor(bgColor);
paint.setStyle(Paint.Style.FILL);
for (int i = 0; i < layout.getLineCount() ; i++) {
drawPath(i,canvas,layout);
}
super.onDraw(canvas);
}
public void updateTextIn(int dur){
new android.os.Handler().postDelayed(new Runnable() {
@Override
public void run() {
setText(getText().toString());
setSelection(getText().toString().length());
}
},dur);
}
public void updateTextImmediate(){
setText(getText().toString());
setSelection(getText().toString().length());
}
public void drawPath(int current, Canvas canvas, Layout layout) {
int left = (int) layout.getLineLeft(current) -SIDE_OFFSET;
int top = layout.getLineTop(current) ;
int right = (int) layout.getLineRight(current) +SIDE_OFFSET;
int bottom = layout.getLineBottom(current);
if (right-left<=1+(SIDE_OFFSET*2))return;
/*
//only one line
if (current == 3 && layout.getLineCount() == 1) {
canvas.drawRoundRect(rectF, 18, 18, paint);
}
//more than one line
else
*/
if (current >= 0) {
//start top left
path.moveTo(left+ OFFSET , top);
//top right - offset
path.lineTo(right - OFFSET, top);
//top right curve to bottom
path.arcTo(right - CORNER, top, right, top + CORNER, -90, 90, false);
//top right to bottom after curve
path.lineTo(right, bottom - OFFSET);
//last rect
if (current+1 == layout.getLineCount()) {
// bottom right curve inner
path.arcTo(right - CORNER, bottom - CORNER, right, bottom, 0, 90, false);
//bottom base line
path.lineTo(left + OFFSET, bottom);
//bottom left arc going toward top left
path.arcTo(left, bottom - CORNER, left+CORNER, bottom, 90, 90, false);
//bottom left to top left after arc
path.lineTo(left , top + OFFSET);
//last arc to complete
path.arcTo(left, top, left+CORNER, top+CORNER, 180, 90, false);
// path.close();
}
//check next rects are bigger ,shorter or same
else {
if (nextRectIsBig(layout,current)){
drawNextBigRect(layout,current);
}
else if (nextRectIsSmall(layout,current)){
drawNextSmallRect(layout,current);
}
//both rect are same
else{
drawNextSameRect(layout,current);
}
}
canvas.drawPath(path, paint);
}
}
private void drawNextSmallRect(Layout layout, int current) {
int next = current+1;
int left = (int) layout.getLineLeft(current)-SIDE_OFFSET ;
int top = layout.getLineTop(current) ;
int right = (int) layout.getLineRight(current)+SIDE_OFFSET ;
int bottom = layout.getLineBottom(current);
int next_left = (int) layout.getLineLeft(next) -SIDE_OFFSET ;
int next_top = layout.getLineTop(next) ;
int next_right = (int) layout.getLineRight(next)+SIDE_OFFSET ;
int next_bottom = layout.getLineBottom(next);
// here is arc from big rect to small rect going down to left
if (right-next_right<CORNER/2){
path.arcTo(right - (CORNER/2f), next_top - (CORNER/2f), right, next_top, 0, 90, false);
}else {
path.arcTo(right - CORNER, next_top - CORNER, right, next_top, 0, 90, false);
}
// now going towards right end of next rect
path.lineTo(next_right+ OFFSET, next_top);
if (next_right-next_left>1+(SIDE_OFFSET*2)){
//inner right curve second rect to bottom
if (right-next_right<CORNER/2){
path.arcTo(next_right , next_top, next_right+ (CORNER/2), next_top + (CORNER/2), 270, -90, false);
}else {
path.arcTo(next_right , next_top, next_right+CORNER, next_top + CORNER, 270, -90, false);
}
//top right to bottom after curve
path.lineTo(next_right, next_bottom - OFFSET);
//bottom right curve inner
path.arcTo(next_right - CORNER, next_bottom - CORNER, next_right, next_bottom, 0, 90, false);
//bottom base line
path.lineTo(next_left + OFFSET, next_bottom);
//bottom left arc going toward top left
path.arcTo(next_left, next_bottom - CORNER, next_left+CORNER, next_bottom, 90, 90, false);
//bottom left to top left after arc
path.lineTo(next_left , next_top - OFFSET);
}else {
//bottom left arc going toward top left
path.arcTo(left, bottom - CORNER, left+CORNER, bottom, 90, 90, false);
//bottom left to top left after arc
// path.lineTo(left , top + OFFSET);
//last arc to complete
// path.arcTo(left, top, left+CORNER, top+CORNER, 180, 90, false);
}
//now check if previous was smaller or same
//here we will pass param 'next' index and check it with prev('current')
// if (prevRectIsBig(layout,next)){
// drawPrevBigRect(layout,next);
// }
// else
if (prevRectIsBig(layout,next)){
drawPrevBigRect(layout,next);
}
//both rect are same
else{
drawPrevSameRect(layout,next);
}
//now it reached to (left,top) of next rect
// path.arcTo(next_left, next_top, next_left+CORNER, next_top+CORNER, 180, 90, false);
}
private void drawNextSameRect(Layout layout, int current) {
int next = current+1;
int left = (int) layout.getLineLeft(current)-SIDE_OFFSET ;
int top = layout.getLineTop(current) ;
int right = (int) layout.getLineRight(current) +SIDE_OFFSET;
int bottom = layout.getLineBottom(current);
int next_left = (int) layout.getLineLeft(next) -SIDE_OFFSET;
int next_top = layout.getLineTop(next) ;
int next_right = (int) layout.getLineRight(next) +SIDE_OFFSET;
int next_bottom = layout.getLineBottom(next);
// here is arc from small rect to big rect going down to right
// path.arcTo(right , next_top - CORNER, right+CORNER, next_top, 180, -90, false);
// now going towards right end of next rect
// path.lineTo(next_right- CORNER, next_top);
//top right curve to bottom
// path.arcTo(next_right - CORNER, next_top, next_right, next_bottom + CORNER, -90, 90, false);
//top right to bottom after curve
// path.lineTo(next_right, bottom - OFFSET);
if (next_right-next_left>1+(SIDE_OFFSET*2)){
//bottom right curve inner
path.arcTo(next_right - CORNER, next_bottom - CORNER, next_right, next_bottom, 0, 90, false);
//bottom base line
path.lineTo(next_left + OFFSET, next_bottom);
//bottom left arc going toward top left
path.arcTo(next_left, next_bottom - CORNER, next_left+CORNER, next_bottom, 90, 90, false);
//bottom left to top left after arc
path.lineTo(next_left , next_top - OFFSET);
}else {
// bottom right curve inner
path.arcTo(right - CORNER, bottom - CORNER, right, bottom, 0, 90, false);
//bottom base line
path.lineTo(left + OFFSET, bottom);
//bottom left arc going toward top left
path.arcTo(left, bottom - CORNER, left+CORNER, bottom, 90, 90, false);
//bottom left to top left after arc
path.lineTo(left , top + OFFSET);
}
//now check if previous was smaller or same
//here we will pass param 'next' index and check it with prev('current')
if (prevRectIsBig(layout,next)){
drawPrevBigRect(layout,next);
}
else if (prevRectIsSmall(layout,next)){
drawPrevSmallRect(layout,next);
}
//both rect are same
else{
drawPrevSameRect(layout,next);
}
//now it reached to (left,top) of next rect
// path.arcTo(next_left, next_top, next_left+CORNER, next_top+CORNER, 180, 90, false);
}
/*
this is for below case
|
|
|=____
*/
private void drawNextBigRect(Layout layout, int current) {
int next = current+1;
int left = (int) layout.getLineLeft(current) -SIDE_OFFSET;
int top = layout.getLineTop(current) ;
int right = (int) layout.getLineRight(current)+SIDE_OFFSET ;
int bottom = layout.getLineBottom(current);
int next_left = (int) layout.getLineLeft(next)-SIDE_OFFSET ;
int next_top = layout.getLineTop(next) ;
int next_right = (int) layout.getLineRight(next) +SIDE_OFFSET;
int next_bottom = layout.getLineBottom(next);
// here is arc from small rect to big rect going down to right
if (next_right-right<CORNER/2){
path.arcTo(right , next_top - (CORNER/2f), right+(CORNER/2f), next_top, 180, -90, false);
}else {
path.arcTo(right , next_top - CORNER, right+CORNER, next_top, 180, -90, false);
}
// now going towards right end of next rect
path.lineTo(next_right- OFFSET, next_top);
//top right curve to bottom
if (next_right-right<CORNER/2){
path.arcTo(next_right - (CORNER/2f), next_top, next_right, next_bottom + (CORNER/2f), -90, 90, false);
}else {
path.arcTo(next_right - CORNER, next_top, next_right, next_bottom + CORNER, -90, 90, false);
}
//top right to bottom after curve
path.lineTo(next_right, next_bottom - OFFSET);
//bottom right curve inner
path.arcTo(next_right - CORNER, next_bottom - CORNER, next_right, next_bottom, 0, 90, false);
//bottom base line
path.lineTo(next_left + OFFSET, next_bottom);
//bottom left arc going toward top left
path.arcTo(next_left, next_bottom - CORNER, next_left+CORNER, next_bottom, 90, 90, false);
//bottom left to top left after arc
path.lineTo(next_left , next_top - OFFSET);
//now check if previous was smaller or same
//here we will pass param 'next' index and check it with prev('current')
// if (prevRectIsBig(layout,next)){
// drawPrevBigRect(layout,next);
// }
// else
if (prevRectIsSmall(layout,next)){
drawPrevSmallRect(layout,next);
}
//both rect are same
else{
drawPrevSameRect(layout,next);
}
//now it reached to (left,top) of next rect
// path.arcTo(next_left, next_top, next_left+CORNER, next_top+CORNER, 180, 90, false);
}
private void drawPrevSameRect(Layout layout, int current) {
int prev = current-1;
int left = (int) layout.getLineLeft(current)-SIDE_OFFSET ;
int top = layout.getLineTop(current) ;
int right = (int) layout.getLineRight(current)+SIDE_OFFSET ;
int bottom = layout.getLineBottom(current);
int prev_left = (int) layout.getLineLeft(prev)-SIDE_OFFSET ;
int prev_top = layout.getLineTop(prev) ;
int prev_right = (int) layout.getLineRight(prev)+SIDE_OFFSET ;
int prev_bottom = layout.getLineBottom(prev);
//below rect (left,top) curve
// path.arcTo(left, top, left+CORNER, top+CORNER, 180, 90, false);
//bottom rect (left,top) to upper rect (left,bottom)
// path.lineTo(prev_left - OFFSET , prev_bottom );
//bottom left inner arc of upper(prev) rect going toward (left,top)
//path.arcTo(prev_left - CORNER, prev_bottom - CORNER, prev_left, prev_bottom, 90, -90, false);
//(left,bottom) to (left,top) after arc of prev rect
// path.lineTo(prev_left , prev_top + OFFSET);
//last arc to complete
path.arcTo(prev_left, prev_top, prev_left+CORNER, prev_top+CORNER, 180, 90, false);
}
private void drawPrevSmallRect(Layout layout, int current) {
int prev = current-1;
int left = (int) layout.getLineLeft(current) -SIDE_OFFSET;
int top = layout.getLineTop(current) ;
int right = (int) layout.getLineRight(current)+SIDE_OFFSET ;
int bottom = layout.getLineBottom(current);
int prev_left = (int) layout.getLineLeft(prev) -SIDE_OFFSET;
int prev_top = layout.getLineTop(prev) ;
int prev_right = (int) layout.getLineRight(prev)+SIDE_OFFSET ;
int prev_bottom = layout.getLineBottom(prev);
//below rect (left,top) curve
if (prev_left-left<CORNER/2){
path.arcTo(left, top, left+(CORNER/2f), top+(CORNER/2f), 180, 90, false);
}else {
path.arcTo(left, top, left+CORNER, top+CORNER, 180, 90, false);
}
//bottom rect (left,top) to upper rect (left,bottom)
path.lineTo(prev_left - OFFSET , prev_bottom );
//bottom left inner arc of upper(prev) rect going toward (left,top)
if (prev_left-left<CORNER/2){
path.arcTo(prev_left - (CORNER/2f), prev_bottom - (CORNER/2f), prev_left, prev_bottom, 90, -90, false);
}else {
path.arcTo(prev_left - CORNER, prev_bottom - CORNER, prev_left, prev_bottom, 90, -90, false);
}
//(left,bottom) to (left,top) after arc of prev rect
path.lineTo(prev_left , prev_top + OFFSET);
//last arc to complete
path.arcTo(prev_left, prev_top, prev_left+CORNER, prev_top+CORNER, 180, 90, false);
}
private void drawPrevBigRect(Layout layout, int current) {
int prev = current-1;
int left = (int) layout.getLineLeft(current) -SIDE_OFFSET;
int top = layout.getLineTop(current) ;
int right = (int) layout.getLineRight(current)+SIDE_OFFSET ;
int bottom = layout.getLineBottom(current);
int prev_left = (int) layout.getLineLeft(prev) -SIDE_OFFSET;
int prev_top = layout.getLineTop(prev) ;
int prev_right = (int) layout.getLineRight(prev)+SIDE_OFFSET ;
int prev_bottom = layout.getLineBottom(prev);
if (right-left>1+(SIDE_OFFSET*2)){
// here is arc from small rect to big rect going top to left
if (left-prev_left<CORNER/2){
path.arcTo(left-(CORNER/2) , top, left, top+(CORNER/2), 0, -90, false);
}else {
path.arcTo(left-CORNER , top, left, top+CORNER, 0, -90, false);
}
//bottom rect (left,top) to upper rect (left,bottom)
path.lineTo(prev_left+ OFFSET , prev_bottom );
//bottom left arc of upper(prev) rect ngoing toward (left,top)
if (left-prev_left<CORNER/2){
path.arcTo(prev_left, prev_bottom - (CORNER/2), prev_left+(CORNER/2), prev_bottom, 90, 90, false);
}else {
path.arcTo(prev_left, prev_bottom - CORNER, prev_left+CORNER, prev_bottom, 90, 90, false);
}
//bottom left to top left after arc
path.lineTo(prev_left , prev_bottom - OFFSET);
}
//last arc to complete
path.arcTo(prev_left, prev_top, prev_left+CORNER, prev_top+CORNER, 180, 90, false);
}
private boolean prevRectIsSmall(Layout layout, int current) {
int prev = current-1;
int left = (int) layout.getLineLeft(current) ;
int prev_left = (int) layout.getLineLeft(prev) ;
return (prev_left -left>= (CORNER/4f));
}
private boolean prevRectIsBig(Layout layout, int current) {
int prev = current-1;
int left = (int) layout.getLineLeft(current) ;
int prev_left = (int) layout.getLineLeft(prev) ;
return (left - prev_left >= (CORNER/4f));
}
private boolean nextRectIsSmall(Layout layout, int current) {
int next = current+1;
int right = (int) layout.getLineRight(current) ;
int next_right = (int) layout.getLineRight(next) ;
return (right - next_right >= (CORNER/4f));
}
private boolean nextRectIsBig(Layout layout,int current) {
int next = current+1;
int right = (int) layout.getLineRight(current) ;
int next_right = (int) layout.getLineRight(next) ;
return (next_right - right >=(CORNER/4f));
}
}
/*
@Override
protected void onDraw(Canvas canvas) {
Layout layout = getLayout();
paint.setTextSize(100f);
paint.setColor(Color.RED);
for (int i = 0; i < layout.getLineCount() ; i++) {
int left = (int)layout.getLineLeft(i) - PADDING;
int top= layout.getLineTop(i) - PADDING;
int right = (int)layout.getLineRight(i) + PADDING;
int bottom = layout.getLineBottom(i) + PADDING;
rect.set(left,top,right,bottom);
rectF.set(rect);
canvas.drawRoundRect(rectF,18,18,paint);
}
super.onDraw(canvas);
}*/
@chihung93
Copy link

Well Done @karandeep
Can not show keyboard :((( on Android 9

@karanatwal
Copy link
Author

I have checked on Android 9, working flawlessly. Can you elaborate more what is happening and phone model ?

@chihung93
Copy link

@karanatwal :
Device: Nokia 3 Plus
OS: 9

Step 1: Add InstaEditext

<androidx.constraintlayout.widget.ConstraintLayout 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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".features.stickers.TextEditorDialogFragment">

    <com.my.InstaEditext
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:minHeight="30dp"
        android:textColor="@color/white"
        android:hint="@string/input_your_text"
        android:gravity="center"
        android:textSize="28sp"
        app:layout_constraintBottom_toTopOf="@id/footer"
        android:background="@android:color/transparent"
        />
....
</androidx.constraintlayout.widget.ConstraintLayout>

Step 2: Run
Step 3: Tap on InstaEditext and the keyboard doesn't show up

One more question: is it work after changing the gravity of EditText?

Thanks

@karanatwal
Copy link
Author

I have Nokia 6.1 Plus OS 9 and it's working fine. I will check later today in sample app. For now you can also try this https://stackoverflow.com/a/49288455/5996106.
I will let you know if got time. For Gravity question I am not sure, I will have to check.

@chihung93
Copy link

chihung93 commented Sep 26, 2019

I really love to hear your reply
1.Video: https://drive.google.com/file/d/14qgJzpiN8HcAKAqFfZc62G7HgMNTHz7-/view?usp=sharing
2.Source code demo: https://drive.google.com/file/d/12VDTOm0qCh84Cb3TtSyOjIOTrd-i9k5_/view?usp=sharing

  1. The BackgroundColorSpan in StackOverflow work well only in gravity = Center.
    But When I change the Gravity from Center to Start/End, its really wrong drawing background.

@rahul01
Copy link

rahul01 commented Feb 20, 2020

@mihirmodiofficial
Copy link

How to add padding on all sides in background?

@mihirmodiofficial
Copy link

when using width wrap_content background not rounded properly some time

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment