[Android] TextView.setError()(一)
来源:互联网 发布:保利地产工资待遇知乎 编辑:程序博客网 时间:2024/06/05 16:26
前言
今天讲述一下TextView.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的核心,主要就是展现友好的提示消息的。我将在下一篇文章中进行详细的介绍。
- [Android] TextView.setError()(一)
- [Android] TextView.setError()(二)
- TextView的setError方法
- android自定义TextView(一)
- Android控件TextView学习一
- Android控件TextView学习一
- [android] EditText的setError文字不显示问题
- Android EditText.setError() - 会弹出一个popupwindow,效果很好
- Android EditText.setError() - 会弹出一个popupwindow,效果很好
- Android中EditText的setError文字不显示的问题
- Android中EditText的setError文字不显示的问题
- Android中EditText的setError文字不显示的问题
- Android用户界面 UI组件--TextView及其子类(一) TextView
- android 总结一 TextView 和Paint
- android自定义View(一)之下划线TextView
- android中常用的控件一TextView
- EditText---setError
- 解决Android 中Edittext在执行setError时有时不显示文字
- Bootstrap 选项卡和面板
- Linux下Clion编译Cmake报错的解决方案
- Android 四大组件之一Service
- memcached全面剖析--2.理解memcached的内存存储
- 变量+shell变量(1)
- [Android] TextView.setError()(一)
- Retrofit 2.0 超能实践(一),okHttp完美支持Https传输
- 【转载】C++的cout高阶格式化操作
- 虚函数
- 全排列的生成使用C++的库函数:next_permutation
- 一个多态性的游戏状态机系统
- html5 拖拽
- [Android讨论] Android Binder机制(超级详尽)
- 关于linux下git使用的一些小结