[Android] TextView.setError()(一)

来源:互联网 发布:保利地产工资待遇知乎 编辑:程序博客网 时间:2024/06/05 16:26

前言

今天讲述一下TextView.setError()这个方法。这个方法主要是作用是对用户友好提示一些信息。比如说在用户输入密码格式不正确的时候,以一种友好的界面形式展现出来。

效果图

EditView设置setError

方法实现

首先看主Aciticity写法:

//代码区域1public class MainActivity extends AppCompatActivity {    private EditText text;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        text = (EditText) findViewById(R.id.text);        Drawable dr = getResources().getDrawable(R.drawable.ad3);        text.setError("提示",dr);    }}

简单起见我直接调用了text的setError方法。

源码分析

接下来是看EditView的setError方法,这个方法继承自TextView:

//代码区域2public void setError(CharSequence error, Drawable icon) {    createEditorIfNeeded();    mEditor.setError(error, icon);    notifyViewAccessibilityStateChangedIfNeeded(            AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);}

在这个方法中,首先调用了createEditorIfNeeded()方法。接下来我们看一下这个方法:

//代码区域3private void createEditorIfNeeded() {    if (mEditor == null) {        mEditor = new Editor(this);    }}

在这个方法中主要是 new了一个Editor并且将TextView自身传给了Editor中的mTextView变量。
我们可以大致瞅一眼Editor的构造函数:

//代码区域4Editor(TextView textView) {    mTextView = textView;    // Synchronize the filter list, which places the undo input filter at the end.    mTextView.setFilters(mTextView.getFilters());    mProcessTextIntentActionsHandler = new ProcessTextIntentActionsHandler(this);}

就可以证明确实如上所说。

接下来回到TextView的setError函数,看第三行调用了mEditor.setError(error, icon);接下来我们查看Editor的setError函数:

//代码区域5public void setError(CharSequence error, Drawable icon) {    mError = TextUtils.stringOrSpannedString(error);    mErrorWasChanged = true;    if (mError == null) {        setErrorIcon(null);        if (mErrorPopup != null) {            if (mErrorPopup.isShowing()) {                mErrorPopup.dismiss();            }            mErrorPopup = null;        }        mShowErrorAfterAttach = false;    } else {        setErrorIcon(icon);        if (mTextView.isFocused()) {            showError();        }    }}

可以看到16行在else当中调用了Editor的setErrorIcon(icon)方法。我们查看其源码:

//代码区域6private void setErrorIcon(Drawable icon) {    Drawables dr = mTextView.mDrawables;    if (dr == null) {        mTextView.mDrawables = dr = new Drawables(mTextView.getContext());    }    dr.setErrorDrawable(icon, mTextView);    mTextView.resetResolvedDrawables();    mTextView.invalidate();    mTextView.requestLayout();}

第二行得到了mTextView的Drawables,并调用了Drawables的setErrorDrawable(icon, mTextView)方法。我们再查看其源码:

//代码区域7public void setErrorDrawable(Drawable dr, TextView tv) {        if (mDrawableError != dr && mDrawableError != null) {            mDrawableError.setCallback(null);        }        mDrawableError = dr;        if (mDrawableError != null) {            final Rect compoundRect = mCompoundRect;            final int[] state = tv.getDrawableState();            mDrawableError.setState(state);            mDrawableError.copyBounds(compoundRect);            mDrawableError.setCallback(tv);            mDrawableSizeError = compoundRect.width();            mDrawableHeightError = compoundRect.height();        } else {            mDrawableSizeError = mDrawableHeightError = 0;        }    }

这个方法可以看到,核心就是将TextView的Drawables的mDrawableError设置为传入的dr,也就是一开始在Acitivity当中传入进来的Drawable。
接着回到到代码区域6,看mTextView.invalidate();这句,此方法会经过多次调用,最后会调用到View的invalidateInternal()方法。我们来看一下这个方法的核心片段:

final AttachInfo ai = mAttachInfo;final ViewParent p = mParent;if (p != null && ai != null && l < r && t < b) {final Rect damage = ai.mTmpInvalRect;damage.set(l, t, r, b);p.invalidateChild(this, damage);}

其中p是ViewParent类型的对象。而ViewParent是一个接口,这个借口的实现类是ViewRoot:

public void invalidateChild(View child, Rect dirty) {      checkThread();      if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);      if (mCurScrollY != 0 || mTranslator != null) {          mTempRect.set(dirty);          dirty = mTempRect;          if (mCurScrollY != 0) {             dirty.offset(0, -mCurScrollY);          }          if (mTranslator != null) {              mTranslator.translateRectInAppWindowToScreen(dirty);          }          if (mAttachInfo.mScalingRequired) {              dirty.inset(-1, -1);          }      }      mDirty.union(dirty);      if (!mWillDrawSoon) {          scheduleTraversals();      }  }  

在实现方法中,注意倒数第三行,scheduleTraversals()这个方法。

public void scheduleTraversals() {      if (!mTraversalScheduled) {          mTraversalScheduled = true;          sendEmptyMessage(DO_TRAVERSAL);      }  }  

实际上这个方法向Handler发送了一个消息。接着我们来看一下这个消息如何被处理的:

public void handleMessage(Message msg) {      switch (msg.what) {      // 、、、      case DO_TRAVERSAL:      // 、、、           performTraversals();      }  }  

performTraversals()这个方法实际上执行了View的onDraw方法,同时mDrawableError也将被绘制出来。代码区域6分析完之后,我们再看代码区域5的最后一个方法 showError()

private void showError() {    if (mTextView.getWindowToken() == null) {        mShowErrorAfterAttach = true;        return;    }    if (mErrorPopup == null) {        LayoutInflater inflater = LayoutInflater.from(mTextView.getContext());        final TextView err = (TextView) inflater.inflate(                com.android.internal.R.layout.textview_hint, null);        final float scale = mTextView.getResources().getDisplayMetrics().density;        mErrorPopup = new ErrorPopup(err, (int)(200 * scale + 0.5f), (int)(50 * scale + 0.5f));        mErrorPopup.setFocusable(false);        // The user is entering text, so the input method is needed.  We        // don't want the popup to be displayed on top of it.        mErrorPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);    }    TextView tv = (TextView) mErrorPopup.getContentView();    chooseSize(mErrorPopup, mError, tv);    tv.setText(mError);    mErrorPopup.showAsDropDown(mTextView, getErrorX(), getErrorY());    mErrorPopup.fixDirection(mErrorPopup.isAboveAnchor());}

这个方法应该是setError的核心,主要就是展现友好的提示消息的。我将在下一篇文章中进行详细的介绍。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子把别人家的玩具玩坏了怎么办 小新和爸妈一起睡觉那他们怎么办 ps画纸画的时候一直在移动怎么办 宝宝磕碰到家具上鼻梁碰破该怎么办 月经推迟11天了怎么办孕测棒单杠 小孩子不小心把蜡笔吃一点怎么办 线切割切割的工件表面有条纹怎么办 苹果手机不能用流量更新吃鸡怎么办 吃鸡更新成雨林如果内存不够怎么办 绝地求生刺激战场背包满了怎么办 绝地求生刺激战场模拟器满了怎么办 绝地求生刺激战场电脑版满了怎么办 绝地求生手游模拟器注册上限怎么办 绝地求生电脑模拟器已达上限怎么办 三星s5锁屏密码忘了怎么办 字画装框的时候起褶皱怎么办 指甲油抹在手上不在指甲上怎么办 我把油画的布割破了怎么办 胜战本领怎么看、走上战场怎么办 胜战本领怎么看 走上战场怎么办 数码相机拍出的相片亮度太亮怎么办 国考照片错了怎么办招生办能改吗 国考英语准考证名字错了怎么办 玻尿酸打鼻子双眼间距好怪怎么办 喝咖啡后胃不舒服想吐怎么办 分期付款买的车不想还款了怎么办 考试时打小抄被同学发现怎么办 生完二胎计生办强制要求上环怎么办 没办二代身份证户口被注销怎么办 川航特价儿童票名字写错怎么办 川航机票名字错一个字怎么办 买飞机票名字打错了一个字怎么办 坐飞机耳朵聋了下飞机还痛怎么办 小孩咳嗽两个月了还不好怎么办 生完小孩肚子瘦不下来怎么办 胆子小一个人在家里都害怕怎么办 怀了双胞胎两个宝宝很挤怎么办 飞机无人陪护如果接机延误该怎么办 过年要坐火车回家 狗狗怎么办 一岁八个月宝宝小腿弯怎么办 2岁宝不愿意坐马桶拉屎怎么办