0x06 中级控件

(1)图形绘制

a. 图形 Drawable

  • Drawable 类型包括图片、色块、画板、背景

  • drawable 目录一般保存描述性 XML 文件,具有具体分辨率的 drawable 目录下保存图片文件

    目录后缀 分辨率等级 举例 应用场景
    ldpi 低分辨率 240×320 -
    mdpi 中分辨率 320×480 -
    hdpi 高分辨率 480×800 4~4.5英寸手机
    xhdpi 加高分辨率 720×1280 5~5.5英寸手机
    xxhdpi 超高分辨率 1080×1920 6~6.5英寸手机
    xxxhdpi 超超高分辨率 1440×2560 7英寸以上平板电脑

b. 形状图形

  • Shape 图形又称形状图形,用来描述常见几何图形,如矩形、圆角矩形、圆形、椭圆形等。形状图形的定义文件是以<shape></spape>为根节点的 XML 描述文件
  1. 形状 shape

    • rectangle:矩形
    • oval:椭圆形,此时<corners>节点会失效
    • line:直线,此时必须设置<stroke>节点
    • ring:圆环
  2. 尺寸 size

    • height:像素类型,图形高度
    • width:像素类型,图形宽度
  3. 描边 stroke

    • color:颜色类型,描边的颜色
    • dashGap:像素类型,每段虚线间的间隔
    • dashWidth:像素类型,每段虚线的宽度
    • width:像素类型,描边的厚度
  4. 圆角 corners

    • bottomLeftRadius:像素类型,左下圆角半径
    • bottomRightRadius:像素类型,右下圆角半径
    • topLeftRadius:像素类型,左上圆角半径
    • topRightRadius:像素类型,右上圆角半径
    • radius:像素类型,统一设置四个圆角半径
  5. 填充 solid

    • color:颜色类型,内部填充的颜色
  6. 间隔 padding

    • top:像素类型,与上方间隔
    • left:像素类型,与左侧间隔
    • right:像素类型,与右侧间隔
    • bottom:像素类型,与下方间隔
  7. 渐变 gradient

    • angle:整形,渐变的起始角度

      取值方法,以表盘为例:0: 9点钟、90: 6点钟、180: 3点钟、270: 12点钟

    • type:字符串类型,设置渐变类型

      • linear:线性渐变
      • radial:放射渐变
      • sweep:滚动渐变
    • centerX:浮点型,圆心 X 坐标

    • centerY:浮点型,圆心 Y 坐标

    • gradientRadius:整形,渐变的半径

    • centerColor:颜色类型,渐变的中间颜色

    • startColor:颜色类型,渐变的起始颜色

    • endColor:颜色类型,渐变的终止颜色

    • useLevel:布尔类型,设置为 true 时无渐变色

举例:

  • 绘图

    <!-- 金色灰边圆角矩形 -->
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#ffdd66" />
    <stroke
    android:width="10dp"
    android:color="#aaaaaa" />
    <corners android:radius="10dp" />
    </shape>

    其中,一个文件对应一个图形

  • 调用

    <Button
    android:id="@+id/btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="金色传说" />
    View vc = findViewById(R.id.btn);
    vc.setBackgroundResource(R.drawable.rect);

    对于按钮默认背景颜色固定为蓝紫色的情况时,可修改 /values/theme/theme.xml 文件,修改<style>标签 parent 属性为:parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge"

c. 九宫格图片

将某张图片设置为背景时,如果图片尺寸太小,则系统会自动拉伸图片使之填满背景

为了解决上述问题,可以将图片转换为 9-Patch 文件,通过调整图片的边缘线来控制图片放大后的效果

  • 上边缘线:控制水平方向的拉伸区域,保证左右两边边框厚度不变
  • 左边缘线:控制垂直方向的拉伸区域,保证上下两边边框厚度不变
  • 下边缘线:控制控件内部的文字左右边界
  • 右边缘线:控制控件内部的文字上下边界

d. 状态列表图形

Button 控件在被按下的前后不同状态下的背景,由状态列表图形控制

  • /res/drawable/btn_selector.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
    android:state_pressed="true"
    android:drawable="@drawable/btn_pressed" />
    <item
    android:drawable="@drawable/btn_normal" />
    </selector>
    • btn_pressed.xml:

      <?xml version="1.0" encoding="utf-8"?>
      <shape xmlns:android="http://schemas.android.com/apk/res/android">
      <solid android:color="#aaaaaa" />
      <stroke
      android:width="10dp"
      android:color="#ffff88" />
      <corners android:radius="10dp" />
      </shape>
    • btn_normal.xml:

      <?xml version="1.0" encoding="utf-8"?>
      <shape xmlns:android="http://schemas.android.com/apk/res/android">
      <solid android:color="#ffdd66" />
      <stroke
      android:width="10dp"
      android:color="#ffff00" />
      <corners android:radius="10dp" />
      </shape>
  • activity_main.xml:

    <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="默认按钮" /> <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/btn_selector"
    android:text="自定义按钮" />

状态类型取值:

状态类型的属性名称 说明 适用的控件
state_pressed 是否按下 按钮
state_checked 是否勾选 单选按钮、复选框
state_focused 是否获取焦点 文本编辑框
state_selected 是否选中 各控件通用

(2)选择按钮

CompoundButton 类是抽象的复合按钮,以下按钮由该类派生而来

graph LR
View-->TextView
-->Button
-->A(CompoundButton)
-->CheckBox
A-->RadioButton
A-->Switch

该类在 XML 文件中主要使用以下两个属性

  • checked:布尔值,指定按钮的勾选状态
  • button:指定勾选图标的图形资源

该类在 Java 文件中主要使用以下四个方法

  • setChecked:设置按钮的勾选状态
  • setButtonDrawable:设置勾选图标的图形资源
  • setOnCheckedChangeListener:设置勾选状态变化的监听器
  • isChecked:判断按钮是否勾选

a. 复选框

<CheckBox
android:id="@+id/cb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="初始状态" />

b. 开关

<Switch
android:id="@+id/sw"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
  • textOn:设置右侧开启时的文本
  • textOff:设置左侧关闭时的文本
  • track:设置开关轨道的背景
  • thumb:设置开关标识的图标
// import ...
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView; public class Activity1 extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener { private TextView tv; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_1);
tv = findViewById(R.id.tv);
((Switch)findViewById(R.id.sw)).setOnCheckedChangeListener(this);
} @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
String res = String.format("当前状态:%s", (b ? "on" : "off"));
tv.setText(res);
}
}

c. 单选按钮

单选按钮要在一组按钮中选中其中一项,用于确定按钮组范围的容器为 RadioGroup,其本质上是一种布局,同一组 RadioButton 和其他控件共同放在 RadioGroup 节点下

<RadioGroup
android:id="@+id/rg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <RadioButton
android:id="@+id/y"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="同意" /> <RadioButton
android:id="@+id/n"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="不同意" /> </RadioGroup>
// import ...
import android.widget.RadioGroup;
import android.widget.TextView; public class Activity1 extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener { private TextView tv; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_1);
tv = findViewById(R.id.tv);
RadioGroup rg = findViewById(R.id.rg);
rg.setOnCheckedChangeListener((RadioGroup.OnCheckedChangeListener) this);
} @Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
tv.setText("选择了 " + ((TextView)findViewById(i)).getText());
}
}
  • check():选中指定资源编号的单选按钮
  • getCheckedRadioButtonId():获取已选中的单选按钮的资源编号
  • setOnCheckedChangeListener():设置单选按钮勾选变化的监听器

(3)文本输入

a. 编辑框 EditText

  • EditText 用于接收软键盘输入的文字,由 TextView 派生而来

  • EditText 具有除 TextView 全部属性外,以下特殊的 XML 属性:

    • inputType:指定输入的文本类型

      输入类型 说明
      text 一般文本
      textPassword 文本密码,由·代替输入内容
      number 整数
      numberSigned 带符号整数
      numberDecimal 浮点数
      numberPassw 数字密码,由·代替输入内容
      datetime 时间日期格式,包括数字、横线、斜线、空格、冒号
      date 日期格式,包括数字、横线、斜线
      time 时间格式,包括数字、冒号
    • maxLength:指定输入的最大长度

    • hint:指定提示文本内容

    • textColorHint:指定提示文本颜色

  • 通过android:background属性修改编辑框背景

    • 背景形状 /drawable/bg.xml

      <?xml version="1.0" encoding="utf-8"?>
      <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@color/white" />
      <stroke
      android:width="1dp"
      android:color="#0000ff" />
      <corners android:radius="5dp" />
      <padding
      android:bottom="5dp"
      android:left="5dp" /> </shape>
    • 设置编辑框

      <EditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:inputType="text"
      android:background="@drawable/bg" />

b. 焦点变更监听器

  • 编辑框点击两次后才会触发点击事件,第一次点击只触发焦点变更事件,第二次点击触发点击事件
  • 若判断是否切换编辑框输入,应当监听焦点变更事件,而非监听点击事件
  • 调用编辑框对象的setOnFocusChangeListener()方法即可在光标切换时触发焦点变更事件

举例:输入并验证 11 位手机号

  • XML

    <EditText
    android:id="@+id/et_ph"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="number"
    android:hint="输入 11 位有效手机号"
    android:background="@drawable/bg"
    android:maxLength="11" /> <EditText
    android:id="@+id/et_pw"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
  • Java

    // import ...
    import android.text.TextUtils;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.TextView;
    import android.widget.Toast; public class Activity1 extends AppCompatActivity implements View.OnFocusChangeListener { private TextView tv;
    private EditText et_1;
    private EditText et_2; @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_1);
    tv = findViewById(R.id.tv);
    et_1 = findViewById(R.id.et_ph);
    et_2 = findViewById(R.id.et_pw);
    et_2.setOnFocusChangeListener(this);
    } @Override
    public void onFocusChange(View view, boolean b) {
    if (b) {
    String phone = et_1.getText().toString();
    if (TextUtils.isEmpty(phone) || phone.length() < 11) {// 判空或位数不足
    // 设置焦点
    et_1.requestFocus();
    // 设置提示
    Toast.makeText(this, "请正确输入 11 位手机号码", Toast.LENGTH_SHORT).show();
    }
    }
    }
    }

c. 文本变化监听器

  • 调用编辑框对象的addTextChangedListener()方法即可注册文本监听器
  • 文本监听器的接口名称为 TextWatch,有以下三个监控方法
    • beforeTextChanged:在文本改变前触发
    • onTextChanged:在文本改变过程中触发
    • afterTextChanged:在文本改变后触发

举例:完成输入指定长度的文本后自动关闭软键盘

  • HideInputMethod.java

    package com.example.test.util;
    
    import android.app.Activity;
    import android.content.Context;
    import android.view.View;
    import android.view.inputmethod.InputMethodManager; public class HideInputMethod { public static void hideInputMethod(Activity act, View v) {
    InputMethodManager imm = (InputMethodManager) act.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
    } }
  • Activity1.java

    // import ...
    import android.text.Editable;
    import android.text.TextWatcher;
    import android.widget.EditText; import com.example.test.util.HideInputMethod; public class Activity1 extends AppCompatActivity { private EditText et_ph; @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_1);
    et_ph = findViewById(R.id.et_ph);
    et_ph.addTextChangedListener(new HideTextWatcher(et_ph, 11));
    } private class HideTextWatcher implements TextWatcher { private EditText et;
    private int ml; public HideTextWatcher(EditText et, int maxLength) { // 构造函数
    this.et = et;
    this.ml = maxLength;
    } @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} @Override
    public void afterTextChanged(Editable editable) {
    String s = editable.toString();
    if (s.length() == ml) {
    HideInputMethod.hideInputMethod(Activity1.this, et);
    }
    }
    }
    }

(4)对话框

a. 提醒 AlertDialog

  • AlertDialog 可以完成常见的交互操作,其借助建造器 AlertDialog.Builder 才能完成参数设置
  • 调用建造器的 create 方法生成对话框实例,在调用对话框实例的 show 方法,在页面上弹出
@Override
public void onClick(View view) {
// 建造器
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 设置标题
builder.setTitle("致用户");
// 设置内容
builder.setMessage("是否确认");
// 设置确认事件
builder.setPositiveButton("确认", (dialogInterface, i) -> {
tv.setText("确认了");
});
// 设置否定事件
builder.setNegativeButton("取消", (dialogInterface, i) -> {
tv.setText("取消了");
});
// 创建对话框
AlertDialog dialog = builder.create();
// 展示对话框
dialog.show();
}

b. 日期 DatePickerDialog

  • 日期选择器 DatePicker 可以让用户选择年月日信息,其并非弹窗模式,不会自动关闭

    <DatePicker
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:datePickerMode="spinner"
    android:calendarViewShown="false" />
    // import ...
    import android.view.View;
    import android.widget.DatePicker;
    import android.widget.TextView; public class Activity1 extends AppCompatActivity implements View.OnClickListener { private TextView tv;
    private DatePicker dp; @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_1);
    tv = findViewById(R.id.tv);
    dp = findViewById(R.id.dp);
    findViewById(R.id.btn).setOnClickListener(this);
    } @Override
    public void onClick(View view) {
    String str = String.format("选择了:%s年%s月%s日", dp.getYear(), dp.getMonth() + 1, dp.getDayOfMonth());
    tv.setText(str);
    }
    }
  • DatePickerDialog 相当于在 AlertDialog 中装载了 DatePicker

    • 监听器OnDateSetLinener负责响应日期选择事件
    • 监听器中方法onDateSet()用于获取用户选择的日期
    // import ...
    import android.app.DatePickerDialog;
    import android.view.View;
    import android.widget.DatePicker;
    import android.widget.TextView; import java.util.Calendar; public class Activity1 extends AppCompatActivity implements View.OnClickListener, DatePickerDialog.OnDateSetListener { private TextView tv; @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_1);
    tv = findViewById(R.id.tv);
    findViewById(R.id.btn).setOnClickListener(this);
    } @Override
    public void onClick(View view) {
    Calendar calendar = Calendar.getInstance();
    DatePickerDialog datePickerDialog = new DatePickerDialog(this, this, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
    datePickerDialog.show();
    } @Override
    public void onDateSet(DatePicker datePicker, int i, int i1, int i2) {
    String str = String.format("选择了:%s年%s月%s日", i, i1 + 1, i2);
    tv.setText(str);
    }
    }

c. 时间 TimePickerDialog

  • 日期选择器 DatePicker 可以让用户选择时、分信息
  • TimePickerDialog 用法与 DatePickerDialog 类似

点我进入下一节


Android 开发入门(4)的更多相关文章

  1. [译]:Xamarin.Android开发入门——Hello,Android Multiscreen深入理解

    原文链接:Hello, Android Multiscreen_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android Multiscreen深入理解. 本 ...

  2. [译]:Xamarin.Android开发入门——Hello,Android深入理解

    返回索引目录 原文链接:Hello, Android_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android深入理解 本部分介绍利用Xamarin开发And ...

  3. [译]:Xamarin.Android开发入门——Hello,Android快速上手

    返回索引目录 原文链接:Hello, Android_Quickstart. 译文链接:Xamarin.Android开发入门--Hello,Android快速上手 本部分介绍利用Xamarin开发A ...

  4. 教我徒弟Android开发入门(一)

    前言: 这个系列的教程是为我徒弟准备的,也适合还不懂java但是想学android开发的小白们~ 本系列是在Android Studio的环境下运行,默认大家的开发环境都是配置好了的 没有配置好的同学 ...

  5. Android开发入门经典【申明:来源于网络】

    Android开发入门经典[申明:来源于网络] 地址:http://wenku.baidu.com/view/6e7634050740be1e650e9a7b.html?re=view

  6. Android开发入门要点记录:四大组件

    cocos2dx跨平台开发中需要了解android开发,昨天快速的浏览了一本Android开发入门教程,因为之前也似懂非懂的写过Activity,Intent,XML文件,还有里面许多控件甚至编程思想 ...

  7. Android开发入门

    教我徒弟Android开发入门(一) 教我徒弟Android开发入门(二) 教我徒弟Android开发入门(三) 出处:http://www.cnblogs.com/kexing/tag/Androi ...

  8. android开发入门经验 ADT Bundle环境搭建

    现在有许多做开发的转做移动端开发,做J2EE的转做Android开发,我也把自己的一些入门经验与大家分享一下,希望能给你带来帮助. 工具/原料 JDK,ADT,JAVA 方法/步骤   开发工具的准备 ...

  9. [Android]Android开发入门之HelloWorld

    引言:在做Unity开发的时候,发现这么个问题,虽然Unity是跨平台的,能够进行Android,IOS,Web,PC等开发,但如果要实现一些稍微系统层的东西,还是需要通过通信,调用原系统的接口(自定 ...

  10. 教我徒弟Android开发入门(二)

    前言: 上一期实现了简单的QQ登录效果,这一期继续对上一期进行扩展 本期的知识点: Toast弹窗,三种方法实现按钮的点击事件监听 正文:   Toast弹窗其实很简单,在Android Studio ...

随机推荐

  1. Glide源码解析三(注册组件)

    转载请标明出处,维权必究: https://www.cnblogs.com/tangZH/p/12900387.html Glide源码解析一,初始化 Glide源码解析二-into方法 Glide源 ...

  2. 为什么(++a)+(++a)=14

    目录 概述 验证 反编译大法 Java 测试 概述 今天有学妹问我,下面这个代码为啥结果是14 int a=5; printf("%d\n",(++a)+(++a)); 我一看,第 ...

  3. 使用rpa打开浏览器并执行js抓取页面元素详情步骤

    这里我们专门开一个文章来写如何在rpa中执行js获取页面元素. 个人觉得,复杂点的需求用js会方便很多,所以后续的文章我都会重点使用js去获取页面元素. 好,正文开始,我们先看一下rpa为我们提供的自 ...

  4. Java 多线程------解决 实现Runnabel接口方式线程的线程安全问题 方式二:同步方法 +总结

    方式二:同步方法* 如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的 1 package bytezero.threadsynchronization; 2 3 4 5 /** ...

  5. 淘宝电商api接口 获取商品详情 搜索商品

    iDataRiver平台 https://www.idatariver.com/zh-cn/ 提供开箱即用的taobao淘宝电商数据采集API,供用户按需调用. 接口使用详情请参考淘宝接口文档 接口列 ...

  6. TLS原理与实践(二)

    主页 个人微信公众号:密码应用技术实战 个人博客园首页:https://www.cnblogs.com/informatics/ 引言 在上一篇博客中,我们通过<一文读懂TLS1.2协议](ht ...

  7. Nginx的负载均衡策略(4+2)

    Nginx的负载均衡策略主要包括以下几种: 轮询(Round Robin):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除.这是Nginx的默认策略,适合服务器配置 ...

  8. pip 安装requirements.txt 的问题

    用新环境 在进行pip 安装的时候, 如果出现不进行安装 ,但是不报错就是满足条件,这个时候重新起一个shell,然后进行pip的安装.

  9. Kettle实战视频教程

    kettle实战视频教程 欢迎关注笔者的公众号: java大师, 每日推送java.kettle运维等领域干货文章,关注即免费无套路附送 100G 海量学习.面试资源哟!!个人网站: http://w ...

  10. chm之已取消到该网页的导航解决办法

    1. 右键单击该 CHM 文件,然后单击"属性". 2. 单击"取消阻止"或者"解除锁定". 3. 双击此 .chm 文件以打开此文件.