为了提高工作效率,对一些常见View的特殊用法作一下总结。
目前创新互联建站已为上千余家的企业提供了网站建设、域名、网络空间、网站托管运营、企业网站设计、长子网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
一、进度条对话框
坑:https://blog.csdn.net/nailsoul/article/details/38870827 (ProgressBar占据位置但是不显示的问题)
最近我的同事孙大姐提个需求:将进度显示框的进度条放到文字上方。
1.使用系统的ProgressDialog
https://www.cnblogs.com/guop/p/5139937.html (圆形进度条与水平进度条) (注意构造方法要传theme,否则有些手机可能看不到进度条。)
看不到进度条的还有一种情况就是没有指定ProgressBar的一个属性:
注意创建ProgressDialog时不要使用Builder来创建,即:
new ProgressDialog.Builder(mContext).create();
用这种方式创建的ProgressDialog会不显示进度条,只会显示纯文字。
原生的进度显示框设置样式为SPINNER,默认进度条放在文字左方,所以无法满足孙大姐的需求。
2.使用AlertDialog自定义View
正确的用法:
progressDialog = new AlertDialog.Builder(mContext).create(); View rootView = LayoutInflater.from(mContext).inflate(R.layout.mprogress_dialog, null); pbBar = rootView.findViewById(R.id.pb_bar); tvMsg = (TextView) rootView.findViewById(R.id.tvMsg); progressDialog.setView(rootView);
注意错误的用法:
new ProgressDialog.Builder(mContext,ProgressDialog.THEME_DEVICE_DEFAULT_DARK).create();
上面的ProgressDialog.Builder实际上还是父类AlertDialog的类,create出来的是AlertDialog,并非ProgressDialog,无法将AlertDialog强制转换成ProgressDialog。
也就无法使用ProgressDialog的特有方法progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER),因此,如果想通过Builder类创建的dialog来实现圆形进度条对话框,
只有自定义view。
3.继承的方式
方式1:直接继承ProgressDialog
研究ProgressDialog的源码可以发现其onCreate方法里:
else{ View view = inflater.inflate(a.getResourceId( com.android.internal.R.styleable.AlertDialog_progressLayout, R.layout.progress_dialog), null); mProgress = (ProgressBar) view.findViewById(R.id.progress); mMessageView = (TextView) view.findViewById(R.id.message); setView(view); }
注意上面的R是com.android.internal.R,如果将布局引用为自己应用的app不就行了。于是继承ProgressDialog准备复写onCreate方法:
可以发现会报各种引用不到的问题,因为这些变量都是父类定义的private变量。
对于变量mContext有public访问方法
对于其他没有public访问方法的private变量,该如何获取呢?
答案:反射 (代码附于文章最后)
还有一项就是系统资源文件com.android.internal.R如何获取呢?
答案:反射 (代码附于文章最后)
com.android.internal.R是无法在java文件里import的
将私有变量和方法用反射代替之后,代码如下:
@Override protected void onCreate(Bundle savedInstanceState) { LayoutInflater inflater = LayoutInflater.from(getContext()); TypedArray a = getContext().obtainStyledAttributes(null, SystemResourceManager.getResourceStyleableIds("AlertDialog"), SystemResourceManager.getResourceAttrId("alertDialogStyle") , 0); if ((int)ReflectManger.getField(ProgressDialog.class,this,"mProgressStyle") == STYLE_HORIZONTAL) { /* Use a separate handler to update the text views as they * must be updated on the same thread that created them. */ ReflectManger.setField(ProgressDialog.class,this,"mViewUpdateHandler",new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); /* Update the number and percent */ int progress = ((ProgressBar)(ReflectManger.getField(ProgressDialog.class,this,"mProgress"))).getProgress(); int max = ((ProgressBar)(ReflectManger.getField(ProgressDialog.class,this,"mProgress"))).getMax(); if (ReflectManger.getField(ProgressDialog.class,this,"mProgressNumberFormat") != null) { String format = (String) ReflectManger.getField(ProgressDialog.class,this,"mProgressNumberFormat"); ((TextView)ReflectManger.getField(ProgressDialog.class,this,"mProgressNumber")).setText(String.format(format, progress, max)); } else { ((TextView)ReflectManger.getField(ProgressDialog.class,this,"mProgressNumber")).setText(""); } if (ReflectManger.getField(ProgressDialog.class,this,"mProgressPercentFormat") != null) { double percent = (double) progress / (double) max; SpannableString tmp = new SpannableString(((NumberFormat)ReflectManger.getField(ProgressDialog.class,this,"mProgressPercentFormat")).format(percent)); tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); ((TextView)ReflectManger.getField(ProgressDialog.class,this,"mProgressPercent")).setText(tmp); } else { ((TextView)ReflectManger.getField(ProgressDialog.class,this,"mProgressPercent")).setText(""); } } }); View view = inflater.inflate(a.getResourceId( SystemResourceManager.getResourceStyleableId("AlertDialog_horizontalProgressLayout"), SystemResourceManager.getResourceLayoutId("alert_dialog_progress")), null); ReflectManger.setField(ProgressDialog.class,this,"mProgress", view.findViewById(SystemResourceManager.getResourceId("progress")) ); ReflectManger.setField(ProgressDialog.class,this,"mProgressNumber", view.findViewById(SystemResourceManager.getResourceId("progress_number")) ); ReflectManger.setField(ProgressDialog.class,this,"mProgressPercent", view.findViewById(SystemResourceManager.getResourceId("progress_percent")) ); setView(view); } else { View view = inflater.inflate(a.getResourceId( SystemResourceManager.getResourceStyleableId("AlertDialog_progressLayout"), R.layout.m_progress_dialog), null); //注意布局中id的引用:android:id="@android:id/progress" ReflectManger.setField(ProgressDialog.class,this,"mProgress", view.findViewById(android.R.id.progress) ); ReflectManger.setField(ProgressDialog.class,this,"mMessageView", view.findViewById(R.id.message) ); setView(view); } a.recycle(); if ((int)ReflectManger.getField(ProgressDialog.class,this,"mMax") > 0) { setMax((int)ReflectManger.getField(ProgressDialog.class,this,"mMax") ); } if ((int)ReflectManger.getField(ProgressDialog.class,this,"mProgressVal") > 0) { setProgress((int)ReflectManger.getField(ProgressDialog.class,this,"mProgressVal") ); } if ((int)ReflectManger.getField(ProgressDialog.class,this,"mSecondaryProgressVal") > 0) { setSecondaryProgress((int)ReflectManger.getField(ProgressDialog.class,this,"mSecondaryProgressVal") ); } if ((int)ReflectManger.getField(ProgressDialog.class,this,"mIncrementBy") > 0) { incrementProgressBy((int)ReflectManger.getField(ProgressDialog.class,this,"mIncrementBy") ); } if ((int)ReflectManger.getField(ProgressDialog.class,this,"mIncrementSecondaryBy") > 0) { incrementSecondaryProgressBy((int)ReflectManger.getField(ProgressDialog.class,this,"mIncrementSecondaryBy") ); } if ( ReflectManger.getField(ProgressDialog.class,this,"mProgressDrawable") != null) { setProgressDrawable((Drawable) ReflectManger.getField(ProgressDialog.class,this,"mProgressDrawable")); } if ( ReflectManger.getField(ProgressDialog.class,this,"mIndeterminateDrawable") != null) { setIndeterminateDrawable((Drawable) ReflectManger.getField(ProgressDialog.class,this,"mIndeterminateDrawable")); } if ( ReflectManger.getField(ProgressDialog.class,this,"mMessage") != null) { setMessage((CharSequence) ReflectManger.getField(ProgressDialog.class,this,"mMessage")); } setIndeterminate((Boolean) ReflectManger.getField(ProgressDialog.class,this,"mIndeterminate")); try { ReflectManger.invokeMethod(ProgressDialog.class,this,"onProgressChanged",null,null); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } super.onCreate(savedInstanceState); }
自定义布局m_progress_dialog.xml 如下:
但是复写的onCreate方法中有个问题
view.findViewById(R.id.message)
结果返回null,但是这个id明明是存在的。但是view.findViewById(android.R.id.progress)怎么不是null呢?
思考半天,看下面的代码:
View view = inflater.inflate(a.getResourceId( SystemResourceManager.getResourceStyleableId("AlertDialog_progressLayout"), R.layout.m_progress_dialog), null);
R.layout.m_progress_dialog只是一个备用布局,跟本就没有加载进去。
将上面的代码稍作修改,将getResourceId方法的第一个值传入一个非法参数0(-1试了不行),这样R.layout.m_progress_dialog就加载了,果然一切正常。
View view = inflater.inflate(a.getResourceId( // SystemResourceManager.getResourceStyleableId("AlertDialog_progressLayout"), 0, R.layout.m_progress_dialog), null);
但是圆形进度条不会显示,上面已经说到了,构造方法要传theme,但是传了theme之后,上面代码又会报下面的错:
android.content.res.Resources$NotFoundException: File res/drawable-xhdpi-v4/dialog_full_holo_light.9.png from xml type layout resource ID #0x1080295
通过debug发现,如果Dialog构造方法加了主题,resId != R.layout.m_progress_dialog
如果Dialog构造方法不加主题 ,
一-2、SeekBar
自定义样式
https://blog.csdn.net/u010029983/article/details/45222257 (推荐)
https://blog.csdn.net/qq_38407076/article/details/83012684
改变游标图片大小:https://www.cnblogs.com/welhzh/p/3711694.html
二、快速创建一个输入框
Builder builder = new Builder(); builder.setTitle(title) .setMessage(message); final EditText et = new EditText(builder.getContext()); et.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); builder.setView(et);
注意动态设置edittext的inputType为密码输入框为:
InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
三、Spinner
快速创建spinner
private void initAreaSpinner(Spinner spinner_area) { ArrayAdapteradapter; adapter = ArrayAdapter.createFromResource(this, R.array.area, android.R.layout.simple_spinner_item); spinner_area.setAdapter(adapter); spinner_area.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView> parent, View view, int position, long id) { switch (position){ case 0: sdk.setBleAreaType(BleAreaType.HENAN); break; case 1: sdk.setBleAreaType(BleAreaType.GUIZHOU); break; case 2: sdk.setBleAreaType(BleAreaType.GUANGXI); break; } } @Override public void onNothingSelected(AdapterView> parent) { } }); spinner_area.setSelection(0); }
四、PopWindow
https://github.com/pinguo-zhouwei/CustomPopwindow (超级方便好用的popwindow)
五、NavigationView
1.修改NavigationView中的Item的Icon大小
https://blog.csdn.net/zuolovefu/article/details/50175245
2.Android NavigationView 中 menu item 字体大小设置
https://blog.csdn.net/TLD_DLT/article/details/79865525
六、TabLayout
1.修改字体大小
https://blog.csdn.net/qq_33919497/article/details/78548198
2.