繼承特定的viewgroup實(shí)現(xiàn)自定義view

先上代碼

public class MinMaxEditText extends LinearLayout implements SaveFormField {
    @Inject
    Bus bus;

    TextView label;
    EditText value;
    TextView charLimit;
    TextView minLimit;
    int charLimitValue;
    private String labelText;
    private DirtyListener listener;
    private String originalString;
    private TextWatcher externalTextWatcher;

    public MinMaxEditText(Context context) {
        super(context);
        init();
    }

    public MinMaxEditText(Context context, AttributeSet attrs) {
        super(context, attrs);

        init();
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MinMaxEditText, 0, 0);

        try {
            setLabel(a.getString(R.styleable.MinMaxEditText_label));
            setCharLimit(a.getInt(R.styleable.MinMaxEditText_charLimit, 0));
            setMinLimit(a.getInt(R.styleable.MinMaxEditText_minLimit, 0));
            setHint(a.getString(R.styleable.MinMaxEditText_hintText));
            showCharLimit(a.getBoolean(R.styleable.MinMaxEditText_showCharLimit, true));
            setIconId((a.getResourceId(R.styleable.MinMaxEditText_iconResource, -1)));
            setLimitTextSize(a.getDimension(R.styleable.MinMaxEditText_limitTextSize, 0));
            setHintTextColorIfExists(a);
            setEditTextTextColorIfExists(a);
        } finally {
            // TypedArray 是單例模式 回收之后  其他地方才能夠使用
            a.recycle();
        }
    }

    private void init() {
        //這里是bus組件的引入 不用管
        GrindrApplication.getGrindrComponent().inject(this);
        //設(shè)置布局方向
        // 特定的布局view 有什么提供的方法 可以看源碼  看提供哪些方法 來用
        setOrientation(VERTICAL);
        // 引入我們要展示的布局文件 并且賦值引用
        View.inflate(getContext(), R.layout.min_max_edit_text, this);
        label = findViewById(R.id.view_edit_profile_edit_label);
        value = findViewById(R.id.view_edit_profile_edit_value);
        charLimit = findViewById(R.id.view_edit_profile_edit_char_limit);
        minLimit = findViewById(R.id.view_edit_profile_edit_min_limit);
        //當(dāng)輸入的內(nèi)容改變的時(shí)候 做一些判斷和處理
        value.addTextChangedListener(new ExternalTextWatcher());
        //這個(gè)地方是設(shè)置輸入軟鍵盤enter鍵的顯示
        value.setImeOptions(EditorInfo.IME_ACTION_DONE);
        //設(shè)置只能單行處理
        setNumLines();
    }

    //自定義listener的名稱 并且添加
    public void addTextChangedListener(TextWatcher tw) {
        this.externalTextWatcher = tw;
    }

    public String getText() {
        return value.getText().toString();
    }

    public void setText(String text) {
        value.setText(text);
        originalString = text;
        setContentDescription();
    }

    public String getLabel() {
        return labelText;
    }

    public void setLabel(String labelText) {
        this.labelText = labelText;
        label.setText(labelText);
        setContentDescription();
    }

    private void setContentDescription() {
        setContentDescription(getResources().getString(R.string.edit_profile_edit_text_content_description, getLabel(), getText(), getText().length(), charLimitValue));
    }

    public void setCharLimit(int charLimitValue) {
        this.charLimitValue = charLimitValue;
        if (charLimitValue == 0) {
            charLimit.setVisibility(View.GONE);
        } else {
            charLimit.setVisibility(View.VISIBLE);
            int numOfChars = charLimit.getText().length();
            charLimit.setText(String.format(Locale.getDefault(), "%d/%d", numOfChars, charLimitValue));
            //這個(gè)地方是設(shè)置edittext輸入字符的最大個(gè)數(shù)
            value.setFilters(new InputFilter[]{createInputFilter(charLimitValue)});
        }
    }

    public void setMinLimit(int charLimitValue) {
        if (charLimitValue == 0) {
            minLimit.setVisibility(View.GONE);
        } else {
            minLimit.setVisibility(View.VISIBLE);
            minLimit.setText(String.format(getResources().getString(R.string.min_max_edit_text_minimum), charLimitValue));

        }
    }

    public void setHint(String hint) {
        value.setHint(hint);
    }

    protected void setNumLines() {
        value.setMaxLines(1);
        value.setSingleLine();
        value.setLines(1);
    }

    public String getHint() {
        return value.getHint().toString();
    }

    public void showCharLimit(boolean show) {
        charLimit.setVisibility(show ? View.VISIBLE : View.GONE);
    }

    public void setIconId(int iconId) {
        if (iconId > 0) {
            value.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(GrindrApplication.getGrindrApplication(), iconId), null, null, null);
        }
    }

    @Override
    public void setDirtyListener(DirtyListener listener) {
        this.listener = listener;
    }

    public EditText getValueView() {
        return value;
    }

    public void update(String value, DirtyListener dirtyListener) {
        setText(value);
        setDirtyListener(dirtyListener);
        getValueView().setHorizontallyScrolling(false);
        getValueView().setMaxLines(Integer.MAX_VALUE);
    }

    private void setLimitTextSize(float limitTextSize) {
        if (limitTextSize != 0) {
            charLimit.setTextSize(TypedValue.COMPLEX_UNIT_PX, limitTextSize);
            minLimit.setTextSize(TypedValue.COMPLEX_UNIT_PX, limitTextSize);
        }
    }

    private void setEditTextTextColorIfExists(TypedArray a) {
        if (a.hasValue(R.styleable.MinMaxEditText_minMaxEditTextColor)) {
            int editTextColor = a.getColor(R.styleable.MinMaxEditText_minMaxEditTextColor, 0);
            value.setTextColor(editTextColor);
        }
    }

    private void setHintTextColorIfExists(TypedArray a) {
        if (a.hasValue(R.styleable.MinMaxEditText_minMaxHintTextColor)) {
            int hintTextColor = a.getColor(R.styleable.MinMaxEditText_minMaxHintTextColor, 0);
            value.setHintTextColor(hintTextColor);
        }
    }

    private class ExternalTextWatcher implements TextWatcher {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            if (externalTextWatcher != null) {
                externalTextWatcher.beforeTextChanged(s, start, count, after);
            }
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (externalTextWatcher != null) {
                externalTextWatcher.onTextChanged(s, start, before, count);
            }
        }

        // 上面兩個(gè)方法安全使用自定義的 listener 代替系統(tǒng)的 listener
        @Override
        public void afterTextChanged(Editable s) {        // s 是改變后的字符串的值
            //判斷數(shù)值是否改變 改變的話用 改變isDirty的值
            if (listener != null && (originalString == null || !originalString.equals(s.toString()))) {
                listener.onFieldDirty(true);
            }
            //設(shè)置字?jǐn)?shù)顯示的值 在這里進(jìn)行組裝
            if (charLimitValue != 0) {
                charLimit.setText(String.format(Locale.getDefault(), "%d/%d", getCurCharSize(s), charLimitValue));
            }
            if (externalTextWatcher != null) {
                externalTextWatcher.afterTextChanged(s);
            }
            setContentDescription();
        }
    }

    protected InputFilter createInputFilter(int charLimitValue){
        return new InputFilter.LengthFilter(charLimitValue);
    }

    protected int getCurCharSize(Editable s){
        return s.length();
    }
}
  • 自定義屬性文件如下
    <declare-styleable name="MinMaxEditText">
        <attr name="label" format="string" />
        <attr name="charLimit" format="integer" />
        <attr name="minLimit" format="integer" />
        <attr name="hintText" format="string" />
        <attr name="minMaxHintTextColor" format="color" />
        <attr name="showCharLimit" format="boolean" />
        <attr name="iconResource" format="reference" />
        <attr name="minMaxEditTextColor" format="color" />
        <attr name="limitTextSize" format="dimension" />
    </declare-styleable>

說明

  • 自定義view的效果如圖所示


    custom1.jpg
  • 功能: 設(shè)置上方的說明文字闽坡,設(shè)置輸入框的最大輸入數(shù)量洼怔,最小輸入數(shù)量谅河,hinttext铡买,hinttext的color,輸入框左邊的圖像標(biāo)志低淡,以及輸入數(shù)量顯示的數(shù)字大小姓言。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蔗蹋,隨后出現(xiàn)的幾起案子何荚,更是在濱河造成了極大的恐慌,老刑警劉巖猪杭,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件餐塘,死亡現(xiàn)場離奇詭異,居然都是意外死亡皂吮,警方通過查閱死者的電腦和手機(jī)戒傻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門税手,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人需纳,你說我怎么就攤上這事芦倒。” “怎么了不翩?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵兵扬,是天一觀的道長。 經(jīng)常有香客問我口蝠,道長器钟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任妙蔗,我火速辦了婚禮傲霸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘眉反。我一直安慰自己昙啄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布禁漓。 她就那樣靜靜地躺著跟衅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪播歼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天掰读,我揣著相機(jī)與錄音秘狞,去河邊找鬼。 笑死蹈集,一個(gè)胖子當(dāng)著我的面吹牛烁试,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拢肆,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼减响,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了郭怪?” 一聲冷哼從身側(cè)響起支示,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鄙才,沒想到半個(gè)月后颂鸿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡攒庵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年嘴纺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了败晴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡栽渴,死狀恐怖尖坤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闲擦,我是刑警寧澤慢味,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站佛致,受9級特大地震影響贮缕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俺榆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一感昼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧罐脊,春花似錦定嗓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至上炎,卻和暖如春恃逻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背藕施。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工寇损, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人裳食。 一個(gè)月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓矛市,卻偏偏與公主長得像,于是被迫代替她去往敵國和親诲祸。 傳聞我的和親對象是個(gè)殘疾皇子浊吏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容