温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android基础View回顾

发布时间:2020-07-24 22:07:04 来源:网络 阅读:331 作者:屠夫章哥 栏目:移动开发

为了提高工作效率,对一些常见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方法:

            Android基础View回顾

            可以发现会报各种引用不到的问题,因为这些变量都是父类定义的private变量。

            对于变量mContext有public访问方法

            Android基础View回顾

            对于其他没有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  如下:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <LinearLayout android:id="@+id/body"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:baselineAligned="false"
            android:paddingStart="8dip"
            android:paddingTop="10dip"
            android:paddingEnd="8dip"
            android:paddingBottom="10dip">
    
            <ProgressBar android:id="@android:id/progress"
                
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:max="10000"
                android:layout_marginEnd="12dip" />
    
            <TextView android:id="@+id/message"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical" />
        </LinearLayout>
     </FrameLayout>

          但是复写的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

            Android基础View回顾

            如果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) {
        ArrayAdapter<CharSequence> adapter;
        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.


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI