Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 自定义编辑文本不在特定位置编辑项目,但始终从最后一个项目开始编辑_Android_Android Edittext - Fatal编程技术网

Android 自定义编辑文本不在特定位置编辑项目,但始终从最后一个项目开始编辑

Android 自定义编辑文本不在特定位置编辑项目,但始终从最后一个项目开始编辑,android,android-edittext,Android,Android Edittext,我正在制作一个自定义的edittext来输入手机号码。这是密码 public class PinEntryEditText extends android.support.v7.widget.AppCompatEditText { private static final String XML_NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android"; protected String mMask = nu

我正在制作一个自定义的edittext来输入手机号码。这是密码

public class PinEntryEditText extends android.support.v7.widget.AppCompatEditText {
    private static final String XML_NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android";

    protected String mMask = null;
    protected StringBuilder mMaskChars = null;
    protected String mSingleCharHint = null;
    protected int mAnimatedType = 0;
    protected float mSpace = 24; //24 dp by default, space between the lines
    protected float mCharSize;
    protected float mNumChars = 4;
    protected float mTextBottomPadding = 8; //8dp by default, height of the text from our lines
    protected int mMaxLength = 4;
    protected RectF[] mLineCoords;
    protected float[] mCharBottom;
    protected Paint mCharPaint;
    protected Paint mLastCharPaint;
    protected Paint mSingleCharPaint;
    protected Drawable mPinBackground;
    protected Rect mTextHeight = new Rect();
    protected boolean mIsDigitSquare = false;

    protected View.OnClickListener mClickListener;
    protected OnPinEnteredListener mOnPinEnteredListener = null;

    protected float mLineStroke = 1; //1dp by default
    protected float mLineStrokeSelected = 2; //2dp by default
    protected Paint mLinesPaint;
    protected boolean mAnimate = false;
    protected boolean mHasError = false;
    protected ColorStateList mOriginalTextColors;
    protected int[][] mStates = new int[][]{
            new int[]{android.R.attr.state_selected}, // selected
            new int[]{android.R.attr.state_active}, // error
            new int[]{android.R.attr.state_focused}, // focused
            new int[]{-android.R.attr.state_focused}, // unfocused
    };

    protected int[] mColors = new int[]{
            Color.GREEN,
            Color.RED,
            Color.BLACK,
            Color.GRAY
    };

    protected ColorStateList mColorStates = new ColorStateList(mStates, mColors);

    public PinEntryEditText(Context context) {
        super(context);
    }

    public PinEntryEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public PinEntryEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
//        this(context, attrs, android.R.attr.editTextStyle);
        init(context, attrs);
    }



    public void setMaxLength(final int maxLength) {
        mMaxLength = maxLength;
        mNumChars = maxLength;

        setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});

        setText(null);
        invalidate();
    }

    private void init(Context context, AttributeSet attrs) {
        float multi = context.getResources().getDisplayMetrics().density;
        mLineStroke = multi * mLineStroke;
        mLineStrokeSelected = multi * mLineStrokeSelected;
        mSpace = multi * mSpace; //convert to pixels for our density
        mTextBottomPadding = multi * mTextBottomPadding; //convert to pixels for our density

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PinEntryEditText, 0, 0);
        try {
            TypedValue outValue = new TypedValue();
            ta.getValue(R.styleable.PinEntryEditText_pinAnimationType, outValue);
            mAnimatedType = outValue.data;
            mMask = ta.getString(R.styleable.PinEntryEditText_pinCharacterMask);
            mSingleCharHint = ta.getString(R.styleable.PinEntryEditText_pinRepeatedHint);
            mLineStroke = ta.getDimension(R.styleable.PinEntryEditText_pinLineStroke, mLineStroke);
            mLineStrokeSelected = ta.getDimension(R.styleable.PinEntryEditText_pinLineStrokeSelected, mLineStrokeSelected);
            mSpace = ta.getDimension(R.styleable.PinEntryEditText_pinCharacterSpacing, mSpace);
            mTextBottomPadding = ta.getDimension(R.styleable.PinEntryEditText_pinTextBottomPadding, mTextBottomPadding);
            mIsDigitSquare = ta.getBoolean(R.styleable.PinEntryEditText_pinBackgroundIsSquare, mIsDigitSquare);
            mPinBackground = ta.getDrawable(R.styleable.PinEntryEditText_pinBackgroundDrawable);
            ColorStateList colors = ta.getColorStateList(R.styleable.PinEntryEditText_pinLineColors);
            if (colors != null) {
                mColorStates = colors;
            }
        } finally {
            ta.recycle();
        }

        mCharPaint = new Paint(getPaint());
        mLastCharPaint = new Paint(getPaint());
        mSingleCharPaint = new Paint(getPaint());
        mLinesPaint = new Paint(getPaint());
        mLinesPaint.setStrokeWidth(mLineStroke);

        TypedValue outValue = new TypedValue();
        context.getTheme().resolveAttribute(R.attr.colorControlActivated,
                outValue, true);
        int colorSelected = outValue.data;
        mColors[0] = colorSelected;

        int colorFocused = isInEditMode() ? Color.GRAY : ContextCompat.getColor(context, R.color.pin_normal);
        mColors[1] = colorFocused;

        int colorUnfocused = isInEditMode() ? Color.GRAY : ContextCompat.getColor(context, R.color.pin_normal);
        mColors[2] = colorUnfocused;

        setBackgroundResource(0);

        mMaxLength = attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID, "maxLength", 4);
        mNumChars = mMaxLength;

        //Disable copy paste
        super.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false;
            }

            public void onDestroyActionMode(ActionMode mode) {
            }

            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                return false;
            }

            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                return false;
            }
        });
        // When tapped, move cursor to end of text.
        super.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setSelection(getText().length());
                if (mClickListener != null) {
                    mClickListener.onClick(v);
                }
            }
        });

        super.setOnLongClickListener(new OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                setSelection(getText().length());
                return true;
            }
        });

        //If input type is password and no mask is set, use a default mask
        if ((getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD) == InputType.TYPE_TEXT_VARIATION_PASSWORD && TextUtils.isEmpty(mMask)) {
            mMask = "\u25CF";
        } else if ((getInputType() & InputType.TYPE_NUMBER_VARIATION_PASSWORD) == InputType.TYPE_NUMBER_VARIATION_PASSWORD && TextUtils.isEmpty(mMask)) {
            mMask = "\u25CF";
        }

        if (!TextUtils.isEmpty(mMask)) {
            mMaskChars = getMaskChars();
        }

        //Height of the characters, used if there is a background drawable
        getPaint().getTextBounds("|", 0, 1, mTextHeight);

        mAnimate = mAnimatedType > -1;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mOriginalTextColors = getTextColors();
        if (mOriginalTextColors != null) {
            mLastCharPaint.setColor(mOriginalTextColors.getDefaultColor());
            mCharPaint.setColor(mOriginalTextColors.getDefaultColor());
            mSingleCharPaint.setColor(getCurrentHintTextColor());
        }
        int availableWidth = getWidth() - ViewCompat.getPaddingEnd(this) - ViewCompat.getPaddingStart(this);
        if (mSpace < 0) {
            mCharSize = (availableWidth / (mNumChars * 2 - 1));
        } else {
            mCharSize = (availableWidth - (mSpace * (mNumChars - 1))) / mNumChars;
        }
        mLineCoords = new RectF[(int) mNumChars];
        mCharBottom = new float[(int) mNumChars];
        int startX;
        int bottom = getHeight() - getPaddingBottom();
        int rtlFlag;
        final boolean isLayoutRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL;
        if (isLayoutRtl) {
            rtlFlag = -1;
            startX = (int) (getWidth() - ViewCompat.getPaddingStart(this) - mCharSize);
        } else {
            rtlFlag = 1;
            startX = ViewCompat.getPaddingStart(this);
        }
        for (int i = 0; i < mNumChars; i++) {
            mLineCoords[i] = new RectF(startX, bottom, startX + mCharSize, bottom);
            if (mPinBackground != null) {
                if (mIsDigitSquare) {
                    mLineCoords[i].top = getPaddingTop();
                    mLineCoords[i].right = startX + mLineCoords[i].height();
                } else {
                    mLineCoords[i].top -= mTextHeight.height() + mTextBottomPadding * 2;
                }
            }

            if (mSpace < 0) {
                startX += rtlFlag * mCharSize * 2;
            } else {
                startX += rtlFlag * (mCharSize + mSpace);
            }
            mCharBottom[i] = mLineCoords[i].bottom - mTextBottomPadding;
        }
    }

    @Override
    public void setOnClickListener(View.OnClickListener l) {
        mClickListener = l;
    }

    @Override
    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
        throw new RuntimeException("setCustomSelectionActionModeCallback() not supported.");
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);
        CharSequence text = getFullText();
        int textLength = text.length();
        float[] textWidths = new float[textLength];
        getPaint().getTextWidths(text, 0, textLength, textWidths);

        float hintWidth = 0;
        if (mSingleCharHint != null) {
            float[] hintWidths = new float[mSingleCharHint.length()];
            getPaint().getTextWidths(mSingleCharHint, hintWidths);
            for (float i : hintWidths) {
                hintWidth += i;
            }
        }
        for (int i = 0; i < mNumChars; i++) {
            //If a background for the pin characters is specified, it should be behind the characters.
            if (mPinBackground != null) {
                updateDrawableState(i < textLength, i == textLength);
                mPinBackground.setBounds((int) mLineCoords[i].left, (int) mLineCoords[i].top, (int) mLineCoords[i].right, (int) mLineCoords[i].bottom);
                mPinBackground.draw(canvas);
            }
            float middle = mLineCoords[i].left + mCharSize / 2;
            if (textLength > i) {
                if (!mAnimate || i != textLength - 1) {
                    canvas.drawText(text, i, i + 1, middle - textWidths[i] / 2, mCharBottom[i], mCharPaint);
                } else {
                    canvas.drawText(text, i, i + 1, middle - textWidths[i] / 2, mCharBottom[i], mLastCharPaint);
                }
            } else if (mSingleCharHint != null) {
                canvas.drawText(mSingleCharHint, middle - hintWidth / 2, mCharBottom[i], mSingleCharPaint);
            }
            //The lines should be in front of the text (because that's how I want it).
            if (mPinBackground == null) {
                updateColorForLines(i <= textLength);
                canvas.drawLine(mLineCoords[i].left, mLineCoords[i].top, mLineCoords[i].right, mLineCoords[i].bottom, mLinesPaint);
            }
        }
    }

    private CharSequence getFullText() {
        if (mMask == null) {
            return getText();
        } else {
            return getMaskChars();
        }
    }

    private StringBuilder getMaskChars() {
        if (mMaskChars == null) {
            mMaskChars = new StringBuilder();
        }
        int textLength = getText().length();
        while (mMaskChars.length() != textLength) {
            if (mMaskChars.length() < textLength) {
                mMaskChars.append(mMask);
            } else {
                mMaskChars.deleteCharAt(mMaskChars.length() - 1);
            }
        }
        return mMaskChars;
    }


    private int getColorForState(int... states) {
        return mColorStates.getColorForState(states, Color.GRAY);
    }

    /**
     * @param hasTextOrIsNext Is the color for a character that has been typed or is
     *                        the next character to be typed?
     */
    protected void updateColorForLines(boolean hasTextOrIsNext) {
        if (mHasError) {
            mLinesPaint.setColor(getColorForState(android.R.attr.state_active));
        } else if (isFocused()) {
            mLinesPaint.setStrokeWidth(mLineStrokeSelected);
            mLinesPaint.setColor(getColorForState(android.R.attr.state_focused));
            if (hasTextOrIsNext) {
                mLinesPaint.setColor(getColorForState(android.R.attr.state_selected));
            }
        } else {
            mLinesPaint.setStrokeWidth(mLineStroke);
            mLinesPaint.setColor(getColorForState(-android.R.attr.state_focused));
        }
    }

    protected void updateDrawableState(boolean hasText, boolean isNext) {
        if (mHasError) {
            mPinBackground.setState(new int[]{android.R.attr.state_active});
        } else if (isFocused()) {
            mPinBackground.setState(new int[]{android.R.attr.state_focused});
            if (isNext) {
                mPinBackground.setState(new int[]{android.R.attr.state_focused, android.R.attr.state_selected});
            } else if (hasText) {
                mPinBackground.setState(new int[]{android.R.attr.state_focused, android.R.attr.state_checked});
            }
        } else {
            mPinBackground.setState(new int[]{-android.R.attr.state_focused});
        }
    }

    public void setError(boolean hasError) {
        mHasError = hasError;
    }

    public boolean isError() {
        return mHasError;
    }

    /**
     * Request focus on this PinEntryEditText
     */
    public void focus() {
        requestFocus();

        // Show keyboard
        InputMethodManager inputMethodManager = (InputMethodManager) getContext()
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.showSoftInput(this, 0);
    }

    @Override
    protected void onTextChanged(CharSequence text, final int start, int lengthBefore, final int lengthAfter) {
        setError(false);
        if (mLineCoords == null || !mAnimate) {
            if (mOnPinEnteredListener != null && text.length() == mMaxLength) {
                mOnPinEnteredListener.onPinEntered(text);
            }
            return;
        }

        if (mAnimatedType == -1) {
            invalidate();
            return;
        }

        if (lengthAfter > lengthBefore) {
            if (mAnimatedType == 0) {
                animatePopIn();
            } else {
                animateBottomUp(text, start);
            }
        }
    }

    private void animatePopIn() {
        ValueAnimator va = ValueAnimator.ofFloat(1, getPaint().getTextSize());
        va.setDuration(200);
        va.setInterpolator(new OvershootInterpolator());
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mLastCharPaint.setTextSize((Float) animation.getAnimatedValue());
                PinEntryEditText.this.invalidate();
            }
        });
        if (getText().length() == mMaxLength && mOnPinEnteredListener != null) {
            va.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    mOnPinEnteredListener.onPinEntered(getText());
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                }

                @Override
                public void onAnimationRepeat(Animator animation) {
                }
            });
        }
        va.start();
    }

    private void animateBottomUp(CharSequence text, final int start) {
        mCharBottom[start] = mLineCoords[start].bottom - mTextBottomPadding;
        ValueAnimator animUp = ValueAnimator.ofFloat(mCharBottom[start] + getPaint().getTextSize(), mCharBottom[start]);
        animUp.setDuration(300);
        animUp.setInterpolator(new OvershootInterpolator());
        animUp.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Float value = (Float) animation.getAnimatedValue();
                mCharBottom[start] = value;
                PinEntryEditText.this.invalidate();
            }
        });

        mLastCharPaint.setAlpha(255);
        ValueAnimator animAlpha = ValueAnimator.ofInt(0, 255);
        animAlpha.setDuration(300);
        animAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer value = (Integer) animation.getAnimatedValue();
                mLastCharPaint.setAlpha(value);
            }
        });

        AnimatorSet set = new AnimatorSet();
        if (text.length() == mMaxLength && mOnPinEnteredListener != null) {
            set.addListener(new Animator.AnimatorListener() {

                @Override
                public void onAnimationStart(Animator animation) {
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    mOnPinEnteredListener.onPinEntered(getText());
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
        }
        set.playTogether(animUp, animAlpha);
        set.start();
    }

    public void setAnimateText(boolean animate) {
        mAnimate = animate;
    }

    public void setOnPinEnteredListener(OnPinEnteredListener l) {
        mOnPinEnteredListener = l;
    }

    public interface OnPinEnteredListener {
        void onPinEntered(CharSequence str);
    }
}
公共类PinEntryEditText扩展了android.support.v7.widget.appcompatiedittext{
私有静态最终字符串XML_NAMESPACE_ANDROID=”http://schemas.android.com/apk/res/android";
受保护字符串mMask=null;
受保护的StringBuilder mMaskChars=null;
受保护的字符串mSingleCharHint=null;
受保护的int mAnimatedType=0;
受保护的浮点mSpace=24;//默认情况下为24 dp,行之间的空间
受保护的浮动麦哈斯化;
受保护浮点数mNumChars=4;
受保护的float mTextBottomPadding=8;//8dp默认情况下,文本距行的高度
受保护的整数mm x长度=4;
受保护的RectF[]mLineCoords;
受保护的漂浮物[]mCharBottom;
保护漆;
受保护涂料;
受保护的油漆和油漆;
受保护的可牵引MPIN背景;
受保护的Rect mTextHeight=new Rect();
受保护的布尔误码方=假;
受保护的View.OnClickListener McClickListener;
受保护的OnPineInteredListener MonPineInteredListener=null;
受保护的浮点mLineStroke=1;//默认为1dp
受保护的浮点mLineStrokeSelected=2;//默认为2dp
受保护的油漆或油漆;
受保护的布尔型人体模型=false;
受保护布尔值mHasError=false;
受保护的ColorStateList mOriginalTextColors;
受保护的int[]mStates=新int[]{
新建int[]{android.R.attr.state_selected},//selected
new int[]{android.R.attr.state_active},//错误
新int[]{android.R.attr.state_focused},//focused
新int[]{-android.R.attr.state_-focused},//未聚焦
};
受保护的int[]mColors=新int[]{
颜色,绿色,
颜色,红色,
颜色,黑色,
颜色:灰色
};
受保护的ColorStateList mColorStates=新的ColorStateList(mStates,mColors);
公共PinEntryEditText(上下文){
超级(上下文);
}
公共PinEntryEditText(上下文、属性集属性){
超级(上下文,attrs);
init(上下文,attrs);
}
公共PinEntryEditText(上下文上下文、属性集属性、int defStyleAttr){
super(上下文、attrs、defStyleAttr);
//这(context、attrs、android.R.attr.editTextStyle);
init(上下文,attrs);
}
公共void setMaxLength(最终整数maxLength){
Mmax长度=最大长度;
mNumChars=最大长度;
setFilters(new-InputFilter[]{new-InputFilter.LengthFilter(maxLength)});
setText(空);
使无效();
}
私有void init(上下文上下文、属性集属性){
float multi=context.getResources().getDisplayMetrics().density;
mLineStroke=多*mLineStroke;
mLineStrokeSelected=多*mLineStrokeSelected;
mSpace=multi*mSpace;//转换为密度的像素
mTextBottomPadding=multi*mTextBottomPadding;//将密度转换为像素
TypedArray ta=context.ActainStyledAttributes(attrs,R.styleable.PinEntryEditText,0,0);
试一试{
TypedValue outValue=新的TypedValue();
ta.getValue(R.styleable.PinEntryEditText\u pinAnimationType,outValue);
mAnimatedType=outValue.data;
mMask=ta.getString(R.styleable.PinEntryEditText\u pinCharacterMask);
mSingleCharHint=ta.getString(R.styleable.PinEntryEditText\u pinRepeatedHint);
mLineStroke=ta.getDimension(R.styleable.PinEntryEditText_pinLineStroke,mLineStroke);
mLineStrokeSelected=ta.getDimension(R.styleable.PinEntryEditText_pinLineStrokeSelected,mLineStrokeSelected);
mSpace=ta.getDimension(R.styleable.PinEntryEditText\u pinCharacterSpacing,mSpace);
mTextBottomPadding=ta.getDimension(R.styleable.PinEntryEditText\u pinTextBottomPadding,mTextBottomPadding);
mIsDigitSquare=ta.getBoolean(R.styleable.PinEntryEditText\u pinbackgroundisquare,mIsDigitSquare);
mPinBackground=ta.getDrawable(R.styleable.PinEntryEditText\u pinBackgroundDrawable);
ColorStateList colors=ta.getColorStateList(R.styleable.PinEntryEditText\u pinLineColors);
如果(颜色!=null){
mColorStates=颜色;
}
}最后{
ta.recycle();
}
mCharPaint=新油漆(getPaint());
mLastCharPaint=新油漆(getPaint());
mSingleCharPaint=新绘制(getPaint());
mLinesPaint=新油漆(getPaint());
MLINESTAINT.设定行程宽度(MLINESTRAKE);
TypedValue outValue=新的TypedValue();
context.getTheme().resolveAttribute(R.attr.colorControlActivated,
超值,正确);
int colorSelected=outValue.data;
mColors[0]=选定的颜色;
int colorFocused=isInEditMode()?Color.GRAY:ContextCompat.getColor(context,R.Color.pin_normal);
mColors[1]=彩色聚焦;
int colorUnfocused=isInEditMode()?Color.GRAY:ContextCompat.getColor(context,R.Color.pin_normal);
mColors[2]=颜色未聚焦;
挫折资源(0);
mMaxLength=attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID,“maxLength”,4);
mNumChars=mm x长度;
//禁用复制粘贴
super.setCustomSelectionActionModeCallback(新的ActionMode.Callback(){
公共布尔onPrepareActionMode(操作模式,菜单){
返回false;
}
公共void onDestroyActionMode(ActionMode模式){
}
公共布尔onCreateActionMode(ActionMode模式,菜单){
返回false;
}
公共布尔值onActionItemClicked(ActionMode模式,菜单项){
返回false;
}
});
//点击时,移动光标
<com.cartoon.customLayout.PinEntryEditText
        android:id="@+id/et_activity_mobile_pinEntryEditText"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:background="@null"
        android:cursorVisible="true"
        android:digits="1234567890"
        android:focusable="true"
        android:imeOptions="actionDone"
        android:inputType="number|phone"
        android:maxLength="10"
        android:textColor="@android:color/white"
        android:textIsSelectable="true"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.40"
        app:pinAnimationType="fromBottom"
        app:pinBackgroundDrawable="@drawable/bg_pin"
        app:pinCharacterSpacing="4dp" />
// When tapped, move cursor to end of text.
    super.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //setSelection(getText().length());
            if (mClickListener != null) {
                mClickListener.onClick(v);
            }
        }
    });
// When tapped, move cursor to end of text.
super.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            setSelection(getText().length());
            if (mClickListener != null) {
                mClickListener.onClick(v);
            }
        }
    });