《第一行代码》阅读笔记(六)——AndroidUI控件(初级)

这一部分书中讲的十分简洁,估计是因为作者考虑到大家刚刚接触到Android,所以没有展开。而控件的使用其实也是非常简单的事情,只要有Java的基础,再了解一些控件的属性,就可以得心应手了。所以笔者在这里补充一些控件的使用,也十分简单。如果暂时不能理解,也不要担心,先往下看,等到明白的时候在回过头来,就会发现真的特别简单。

TextView

属性

        android:id="@+id/txv1"

当前控件唯一标识符,以后的交互中会经常使用,相当于这个控件的name

        android:layout_width="match_parent"
        android:layout_height="wrap_content"

控件的宽度和高度,每个控件都有,除了可以指定数据还可以使用match_ parent、 fill_ parent和wrap_ content。现在fill_ parent已经不用了。关于match_ parent和wrap_ content书中是这样讲的,我觉得还是挺简单明了的。

——第一行代码
然后使用android:layout_ width 和android: layout_ height 指定了控件的宽度和高度。Android 中所有的控件都具有这两个属性,可选值有3种: match_ parent、 fill_ parent和wrap_ content。 其中match_ parent 和fill_ parent 的意义相同,现在官方更加推荐使用match_ parent。 match_ parent 表示让当前控件的大小和父布局的大小-样,也就是由父布局来决定当前控件的大小。wrap_ content 表示让当前控件的大小能够刚好包含住里面的内容,也就是由控件内容决定当前控件的大小。所以上面的代码就表示让TextView的宽度和父布局一样宽,也就是手机屏幕的宽度,让TextView的高度足够包含住里面的内容就行。当然除了使用上述值,你也可以对控件的宽和高指定一个固定的大小,但是这样做有时会在不同手机屏幕的适配方面出现问题。

总结起来就是一句话,match_ parent是填充父布局,wrap_ content是自己有多少占多少。

   android:gravity="center"

指定控件中内容的位置,书中是这样介绍的

——第一行代码
我们使用android:gravity来指定文字的对齐方式,可选值有top、bottom. left、right、center等,可以用来同时指定多个值,这里我们指定的center, 效果等同于center_vertical|center_ horizontal, 表示文字在垂直和水平方向都居中对齐。

    android:text="This is a text"
    android:textColor="#00ff00"
    android:textSize="60sp" />

这三个简单明了,分别是文字,文字颜色和文字大小。
这里附上一个文字颜色表,仅供参考

Button

Button按钮的属性基本上和TextView相似,值得注意的是

  1. 可以使用android:textAllCaps="false"来禁止Button中的文字转化成为大写
  2. 可以在Activity里面为按钮绑定监听器事件
Button btnId = (Button) findViewById(R.id.btn_id);
        btnId.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               //此处添加逻辑
            }
        });

EditText

EditText是一个对话框,用处十分广泛,像QQ、短信等等,而控件属性大同小异,而文中提到比较特殊的就是

  1. android:hint=“xxx” 类似于提示,在登录界面时,每个对话框会提示需要输入的是账号或者密码,当输入文字时消失。
  2. android:maxLines=“2”。因为之前设置的宽度是可变的,随着输入内容的不断增加会变得不好看,设置了这个最大行数,就可以在超过两行时自动向下拉取进度条,而不调整控件大小。

ImageView

展示图片的控件,通过android:src来指定图片的位置,图片一般存放在drawable中,可以存放不同分辨率的图片,这样在不同设备上都可以显示。

ProgressBar

是界面上显示的一个进度条

为了实现进度条的功能,需要调整控件的可见性。

——第一行代码
Android控件的可见属性。所有的Android控件都具有这个属性,可以通过android:visibility进行指定,可选值有3种: visible、 invisible 和gone。visible 表示控件是可见的,这个值是默认值,不指定android:visibility时,控件都是可见的。invisible 表示控件不可见,但是它仍然占据着原来的位置和大小,可以理解成控件变成透明状态了。gone 则表示控件不仅不可见,而且不再占用任何屏幕空间。我们还可以通过代码来设置控件的可见性,使用的是setVisibility()方法,可以传人View. VISIBLE、View. INVISIBLE和View. GONE这3种值。

其中有一个属性可以设置进度条的格式,就是Style。

<ProgressBar
            android:id="@+id/pb_normal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <ProgressBar
            android:id="@+id/pb_small"
            style="?android:attr/progressBarStyleSmall"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <ProgressBar
            android:id="@+id/pb_large"
            style="?android:attr/progressBarStyleLarge"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <ProgressBar
            android:id="@+id/pb_horizontal"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />


        <ProgressBar
            android:id="@+id/pb_horizontal_default"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:max="100"
            android:progress="50"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

对应

很简单对不对。其中还可以通过android:max="100",android:progress="50" 来实现进度条的模拟。

但是这不是一个静止的画面,需要让他动起来。怎么做呢?主要的思路就是,先开一个子线程,在线程中加载耗时操作,并发送信息。然后,通过Handler机制接受信息,更新进度条,完成后隐藏进度条。

第一步:声明变量

private ProgressBar progressBar;
    private int mProgress = 0;
    private Handler mHandler;

这个不多说,mProgress用来记录进度,默认是零。然后还有一些绑定布局啥的就不说了。

第二步:开辟一个线程

new Thread(new Runnable() {
            @Override
            public void run() {               
            }          
        }).start();

这个不解释了吧,实例一个Thread,以匿名内部类的方式传入Runable类,并且重写run方法,然后start()运行run中的内容。

第三步:写一个耗时方法

  private int doWork() {
                mProgress += Math.random() * 10;
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return mProgress;
            }

Math.random()就是生成0到1之间的随机小数,这里+=包括一个强转。之后每次睡2s。

第四步:

while (true) {
                    mProgress = doWork();
                    Message m = new Message();
                    if (mProgress < 100) {
                        m.what = 0x111;
                        mHandler.sendMessage(m);
                    } else {
                        m.what = 0x110;
                        mHandler.sendMessage(m);
                        break;
                    }
                }

首先就是把doWork()的进度传给mProgress,全局变量一般带个m。然后实例一个Message用来传递信息,如果mProgress小于100,m.what为一个值。大于100说明任务完成,传另外一个值,然后别忘记break。

第五步:实例Handler

mHandler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                if (msg.what == 0x111) {
                    progressBar.setProgress(mProgress);
                                 } else {
                    Toast.makeText(MainActivity.this, "耗时操作已完成", Toast.LENGTH_SHORT).show();
                    progressBar.setVisibility(View.GONE);
                }
            }
        };

实例一个Handler,然后重写handleMessage方法。传入的msg就是之前发送的msg,然后判断一下,更改progress的值,或者完成,隐藏控件。

好了,运行测试,就可以体验动态进度条了。下面附上一个完整的文件,结构更清晰。

public class MainActivity extends AppCompatActivity {
    private ProgressBar progressBar;
    private int mProgress = 0;
    private Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        progressBar = findViewById(R.id.p);

        mHandler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                if (msg.what == 0x111) {
                    progressBar.setProgress(mProgress);
                                 } else {
                    Toast.makeText(MainActivity.this, "耗时操作已完成", Toast.LENGTH_SHORT).show();
                    progressBar.setVisibility(View.GONE);
                }
            }
        };

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    mProgress = doWork();
                    Log.i("TAG", "handleMessage: " + mProgress);
                    Message m = new Message();
                    if (mProgress < 100) {
                        m.what = 0x111;
                        mHandler.sendMessage(m);
                    } else {
                        m.what = 0x110;
                        mHandler.sendMessage(m);
                        break;
                    }
                }
            }

            private int doWork() {
                mProgress += Math.random() * 10;
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return mProgress;
            }
        }).start();
    }

}

还有一种Handler传递方式,我觉得更加符合咱们思维。是通过sendEmptyMessage直接传递Message.what,省去了实例化Message的步骤。而接收的时候使用Switch判断。附上实例

public class MainActivity extends AppCompatActivity {
    ……

    @Override
    protected void onCreate(Bundle savedInstanceState) {
          ……

        mHandler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                switch (msg.what) {
                    case 100:
                        progressBar.setProgress(mProgress);
                        break;
                    case 200:
                        Toast.makeText(MainActivity.this, "耗时操作已完成", Toast.LENGTH_SHORT).show();
                        progressBar.setVisibility(View.GONE);
                        break;
                    default:
                        break;
                }
            }
        };

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    mProgress = doWork();
                    if (mProgress < 100) {
                        mHandler.sendEmptyMessage(100);
                    } else {
                        m.what = 0x110;
                        mHandler.sendEmptyMessage(200);
                        break;
                    }
                }
            }

            private int doWork() {
                 ……
            }
        }).start();
    }

}

AlertDialog

AlertDialog是一个对话框,在所有控件之上,可以屏蔽其他控件的交互能力。也非常简单。

先展示几个效果

  1. 普通提示对话框

//双选对话框
                AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();
                alertDialog.setIcon(R.mipmap.ic_launcher);
                alertDialog.setTitle("乔布斯");
                alertDialog.setMessage("活着就是为了改变世界,难道还有还有其他原因吗?");
                alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "是", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(MainActivity.this, "您单击了是按钮", Toast.LENGTH_SHORT).show();
                    }
                });
                alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "否", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(MainActivity.this, "您单击了否按钮", Toast.LENGTH_SHORT).show();
                    }
                });
                alertDialog.show();

具体介绍一下用到的方法吧:

  • setTitle:设置对话框的标题,比如“提示”、“警告”等;
  • setMessage:设置对话框要传达的具体信息;
  • setIcon: 设置对话框的图标;
  • setCancelable: 点击对话框以外的区域是否让对话框消失,默认为true;
  • setOnShowListener:对话框显示时触发的事件;
  • setOnCancelListener:对话框消失时触发的事件。
  • setButton:传递了三个参数,第一个就是按钮的类型,BUTTON_NEUTRAL、BUTTON_NEGATIVE和BUTTON_POSITIVE,分别对应的就是图中的对的选择和错的选项。还有个中立选项,位置在弹出的对话框的最左边。第二个参数就是按钮上面显示的文字。第三个参数就是点击事件。
  1. 列表提示对话框

 //带四个列表项的对话框
                final String[] items = new String[]{"123", "1233", "456", "789"};
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setIcon(R.mipmap.ic_launcher);
                builder.setTitle("请选择你喜欢的标题");
                builder.setItems(items, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(MainActivity.this, "您选择了【" + items[which]
                                + "】", Toast.LENGTH_SHORT).show();
                    }
                });
                builder.create().show();

和普通对话框不一样的地方就是setItems,传入的第一个参数就是需要显示的内容,是一个字符串数组。第二个参数就是点击事件。

这里还有个不一样的地方,就是普通对话是直接操作的AlertDialog对象,而这里是操作了一个AlertDialog内部类Builder对象。两者之间的关系就是Builder对象的create方法可以生成一个AlertDialog对象。

  1. 单选对话框

 final String[] items = new String[]{"1", "2", "3", "4", "5"};
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setIcon(R.mipmap.ic_launcher);
                builder.setTitle("请选择你喜欢的标题");
                builder.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(MainActivity.this, "您选择了【" + items[which]
                                + "】", Toast.LENGTH_SHORT).show();
                    }
                });
                builder.setPositiveButton("确定", null);
                builder.create().show();

只是把setItems改成setSingleChoiceItems,同时多了一个参数,就是第二个0,这是默认选择的选择。这里使用

  • setPositiveButton:设置正面按钮,表示“积极”、“确认”的意思,第一个参数为按钮上显示的文字,下同;
  • setNegativeButton:设置反面按钮,表示“消极”、“否认”、“取消”的意思;
  • setNeutralButton:设置中立按钮;

实现了AlertDialog.setButton的方法。

  1. 多选对话框

final boolean[] checkedItem = new boolean[]{false,true,false,true,false};
                final String[] items = new String[]{"1", "2", "3", "4", "5"};
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setIcon(R.mipmap.ic_launcher);
                builder.setTitle("请选择你喜欢的标题");
                builder.setMultiChoiceItems(items, checkedItem, new DialogInterface.OnMultiChoiceClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        checkedItem[which] = isChecked;
                    }
                });
                builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        String result = "";
                        for (int i = 0; i < checkedItem.length; i++) {
                            if (checkedItem[i]) {
                                result+=items[i]+"";
                            }
                        }
                        if (!"".equals(result)) {
                            Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
                        }
                    }
                });
                builder.create().show();

之前有Single,自然就有Multi,所以设置函数是setMultiChoiceItems。参数分别是显示文字数组,默认选项数组(boolean数组)和点击事件。

ProgressDialog

ProgressDialog和AlertDialog非常相似,只不过多了一个进度条,感觉更像是安装或者下载时候的提示。用法等于AlertDialog+ProgressBar相似。

——第一行代码
注意,如果在setCancelable()中传人了false, 表示ProgressDialog是不能通过Back键取消掉的,这时你就一定要在代码中做好控制,当数据加载完成后必须要调用ProgressDialog 的dismiss ()方法来关闭对话框,否则ProgressDialog将会一直存在。

posted @ 2020-07-22 22:55  朱李洛克  阅读(324)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css