Android疑难杂症总结(一)——控件篇

目录

前言

1.控件冲突

1.1 ScrollView与内部嵌套的TextView滚动冲突

1.2 ScrollView嵌套RecyclerView滑动冲突

1.3 ScrollView嵌套ScrollView的滑动冲突

 2.控件改造

2.1 Spinner中的文字居中

2.2 AlertDialog输入框确认不关闭

2.3 非Activity(Fragment)下弹出AlertDialog

2.4 AlertDialog宽度失效问题

 3.依赖冲突或失效

3.1 ButterKnife

 4.其它问题

4.1 FrameLayout点击事件穿透

4.2 控件无故报错

4.3 ListView Item焦点无法获取

4.4 EditText无法单行显示


前言

      平时开发经常遇到各种UI控件问题,下面这些是个人日常开发中遇到的问题及解决方案整理,长期更新和整理。

本文着重问题解决过程,如果要理解产生问题根本原因,请自行百度研究。

1.控件冲突

主要介绍原生控件互相嵌套造成的滑动冲突的解决方案。

1.1 ScrollView与内部嵌套的TextView滚动冲突

当ScrollView内部TextView时,textview文字过多无法滚动,要想textview滚动必须按照以下步骤:

步骤:

  1. textview的滚动设置

        为控件添加属性scrollbars=“vertical”,

    2、然后代码设置

textview.setMovementMethod(ScrollingMovementMethod.getInstance());

   3、此时textview并没有滚动,为textview加入以下代码即可

@Override

    public boolean onTouch(View v, MotionEvent event) {

        // TODO Auto-generated method stub

        if(event.getAction()==MotionEvent.ACTION_DOWN){

            //通知父控件不要干扰

            v.getParent().requestDisallowInterceptTouchEvent(true);

        }

        if(event.getAction()==MotionEvent.ACTION_MOVE){

            //通知父控件不要干扰

            v.getParent().requestDisallowInterceptTouchEvent(true);

        }

        if(event.getAction()==MotionEvent.ACTION_UP){

            v.getParent().requestDisallowInterceptTouchEvent(false);

        }

        return false;

    }

});

1.2 ScrollView嵌套RecyclerView滑动冲突

https://www.jianshu.com/p/5dfc90656665

1.3 ScrollView嵌套ScrollView的滑动冲突

外面的ScrollView正常滑动,但是里面的那个ScrollView动不了,

解决方案:重新定义里面的ScrollView,新建一个类继承ScrollView,在自定义控件中重写onInterceptTouchEvent就告诉所有父View:不要拦截事件,让我消费!!

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

    getParent().requestDisallowInterceptTouchEvent(true);

    return super.onInterceptTouchEvent(ev);

}

 2.控件改造

主要介绍原生控件不支持某些功能且不修改原生控件的情况下的解决方案。

2.1 Spinner中的文字居中

(1)方法1

spinner.setOnItemSelectedListener(new OnItemSelectedListener(){

                @Override

                public void onItemSelected(AdapterView<?> parent, View view, int position, long id){

                   TextView tv = (TextView)view;

                    tv.setTextColor(getResources().getColor(R.color.white));    //设置颜色



                     tv.setTextSize(12.0f);    //设置大小



                     tv.setGravity(android.view.Gravity.CENTER_HORIZONTAL);   //设置居中

                }

                @Override

                public void onNothingSelected(AdapterView<?> parent){}

            });

(2)方法2

https://blog.csdn.net/qq_26607985/article/details/52849809?locationNum=4&fps=1

2.2 AlertDialog输入框确认不关闭

       有时候用到Android AlertDialog自定义输入框,但是输入框是不支持验证的,不管点击确认还是取消都关闭,当我们需要对输入的字符串验证时可以做如下处理: 

EditText inputServer = new EditText(this);

        inputServer.setHint("请输入密码");

        AlertDialog alertDialog = new AlertDialog.Builder(this)

        .setCancelable(false)

        .setMessage("XXXXX!")

        .setTitle("XXX!!!")

        .setIcon(android.R.drawable.ic_dialog_info)

        .setView(inputServer)

        .setNegativeButton("取消", new DialogInterface.OnClickListener() {

            @Override

            public void onClick(DialogInterface dialog, int which) {

                dialog.dismiss();

                finish();

            }

        })

        .setPositiveButton("确定", null)

        .show();



        alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                String input = inputServer.getText().toString().trim();

                if(input.isEmpty()) {

                    inputServer.setHint("请输入密码!");

                    return;

                }

                if (input.equals(password)) {

                    alertDialog.dismiss();

                }else {

                    inputServer.setText("");

                    inputServer.setHint("密码错误,请联系管理员获取!");

                    return;

                }

            }

        });

2.3 非Activity(Fragment)下弹出AlertDialog

我们知道,在非activityFragment)下使用Application的上下文来创建AlertDialog(android.app.AlertDialog包下,不是v7包,会报如下错误:


                                                 android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application

at android.view.ViewRootImpl.setView(ViewRootImpl.java:578)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:282)

 如果要弹出也是可以的,解决方案如下:

1.添加权限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />  

2. 为AlertDialog添加如下设置

AlertDialog.Builder builder = new AlertDialog.Builder(MyApplication.getContext());
                    builder.setTitle("提示")
                            .setMessage("是否?")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    dialog.dismiss();
                                }
                            });
                    AlertDialog alertDialog = builder.create();
                 alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);//重点   
                    alertDialog.show();

上面是针对android.app包的AlertDialog才能正常使用,但如果你用 android.support.v7.app.AlertDialog,会如下报错:

 java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
                                                                      at android.support.v7.app.AppCompatDelegateImplV9.createSubDecor(AppCompatDelegateImplV9.java:354)
                                                                      at android.support.v7.app.AppCompatDelegateImplV9.ensureSubDecor(AppCompatDelegateImplV9.java:323)

根据错误提示对AlertDialog修改如下: 

        AlertDialog.Builder builder = new AlertDialog.Builder(MyApplication.getContext(), android.support.v7.appcompat.R.style.Theme_AppCompat_Dialog);
//省略,同上

细心的你会发现上面的弹出框是黑色的(测试系统原生Android5.0),下面推荐一个好看的主题:

        AlertDialog.Builder builder = new AlertDialog.Builder(MyApplication.getContext(), android.support.v7.appcompat.R.style.Theme_AppCompat_Light_Dialog_Alert);

结果是白色。

2.4 AlertDialog宽度失效问题

       有时候用到Android AlertDialog自定义输入框,宽度设置的比较大(平板上),发现无效,可以通过下面方法修改:

            Window window = dialogBuilder.getWindow();
            WindowManager.LayoutParams lp = window.getAttributes();
            lp.gravity = Gravity.CENTER;
            lp.width = WindowManager.LayoutParams.WRAP_CONTENT;//宽高可设置具体大小
            lp.width  = 1000;
            dialogBuilder.getWindow().setAttributes(lp);

 3.依赖冲突或失效

主要介绍集成第三方依赖时出现的各种小问题而导致依赖无法使用或者失效。

3.1 ButterKnife

(1)假如module A中引入ButterKnife(使用compile或者api引入依赖)时,当主工程(app)引入module A时,导致主工程使用ButterKnife时被注解的控件实例为空,从而空指针异常。

解决方案:在主工程依赖节点dependencies 添加注解处理器即可(注解处理器只对当前module有效),不用再添加依赖(因为你的module已经引入了依赖)。

    //注意版本和你的实际依赖版本一致
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'

 4.其它问题

4.1 FrameLayout点击事件穿透

在点击的布局中增加android:clickable="true"的属性,点击事件就不能再向下层传递,例如下图:

 

点击红色区域不会把事件传递给RecyclerView列表条目

4.2 控件无故报错

问题:

比如:RecyclerView打开报错

                            android.view.InflateException: Binary XML file line #2: Error inflating class <unknown>

解决方法:

检查主布局和条目布局background和textcolor是否针对drawable-v21和drawable-v19适配,如果只有drawable-v21,跑在Android 4.4会包上面的错误

4.3 ListView Item焦点无法获取

问题:

使用ListView做下拉列表时,假如listview的item中有Button,ImageButton,CheckBox等会强制获取焦点的view。此时,listview的item无法获取焦点,从而无法被点击。

解决方法:

给item的根布局增加以下属性android:descendantFocusability="blocksDescendants"

设置之后,Button获取焦点,item中其他控件也可以获取焦点

4.4 EditText无法单行显示

应用中使用了EditText并设置了android:maxLines="1",但是给该EditText赋值事发现它还是多行显示,于是又设置了android:singleLine="true",问题解决了

API说的很明确,maxLines是设置TextView最多展示多少行,但是在可编辑的Text中,必须要与singleLine一起使用才能使maxLinesAPI生效。

singleLine,当文案长度大于TextView的宽度之后,文案就会以水平滑动的方式显示,而不是以多行展示。而且,EditText设置singleLine之后,输入文案时就不会有回车换行。

结论:要控制EditText单行显示需要同时设置android:singleLine="true"和android:maxLines="1";

猜你喜欢

转载自blog.csdn.net/u011082160/article/details/90718144