主要内容:
◼ 界面布局
◼ 常用UI组件编程
◼ 多种监听器用法
◼ ImageView图像加载方法
◼ Adapter适配器
◼ 自定义布局
◼ Handler.postDelayed定时器
◼ CountDownTimer倒计时
◼ ExoPlayer媒体播放器
界面布局
◼ 新建一个Module(相当于新app)
◼ 应用名称为:UIDemo
◼ Activity默认:MainActivity
新建Module时注意命名:
界面布局
◼ 布局作用:
◼ 将应用的外观代码(xml)与控制其行为的代码(java)分开(表现层和控制层分离),调整用户界面时,无需更改程序的源代码。
◼ 基本布局:
◼ 约束布局 ConstraintLayout
◼ 线性布局 LinearLayout
1.ConstraintLayout
◼ 默认布局,依靠约束关系来确定位置
◼ 能够灵活定位和调整界面元素的大小
◼ 无任何嵌套,减少布局层级,优化渲染性能
◼ 能完全代替其他布局
基线对齐示例:
2.LinearLayout
◼ 线性布局:界面元素都在一行(水平方向)或一列(垂直方向),可嵌套
◼ 通过 android:orientation 属性指定布局方向:
◼ android:orientation="horizontal"
水平布局 (默认)
◼ android:orientation="vertical"
垂直布局
线性布局示例:
◼ 嵌入一个垂直布局
• android:orientation = “vertical”
• android:layout_width = “match_parent”
• android:layout_height = “wrap_content”
• android:gravity = “center_horizontal”
改为”horizontal” 水平布局
View 与 ViewGroup 的概念
◼ Android中所有的UI元素都是使用View和ViewGroup对象建立的。
◼ View是一个可以将一些信息绘制在屏幕上并与用户产生交互的对象。例如Button、TextView等
◼ ViewGroup是一个包含多个的View和ViewGroup的容器,用来定义UI布局。例如ConstraintLayout、LinearLayout、RadioGroup等。
◼ View类作为界面开发的超类,所有的界面开发都与View有关。
常用UI组件
基本属性
基本属性 |
描述 |
id |
组件唯一标识 |
layout_width |
组件的宽度 |
layout_height |
组件的高度 |
text |
文本内容 |
textColor |
字体颜色 |
textSize |
字体大小 ==注:字体大小默认单位为 sp,宽高默认单位是 dp== |
textStyle |
字体样式(normal|bold|italic) |
backgroundTint |
背景颜色 |
gravity |
内部元素对齐方式:left|center|right|center_horizontal|center_vertical等(父容器要求子元素如何对齐) |
layout_gravity |
容器中的子元素相对父容器的对齐方式(取值同上) |
layout_weight |
用来分配空间占比权重(常用于线性布局 + layout_width=”0dp”配合) |
layout_width 和 layout_height 为必填的2个属性,可以设置数值(dp),也可以使用:
wrap_content:根据内容自动扩展以适应内容大小
match_parent:控件大小填满整个父容器
ayout_weight 宽度占比示例:
1.TextView
常用属性 |
描述 |
background |
背景颜色(或背景图片) |
autoLink |
文本自动识别为web超链接、Email地址等
|
autoLink 用法
常用方法
1 2 3 4 5 6 7
| ◼ 示例: TextView tv = (TextView) findViewById(R.id.***); String str = tv.getText().toString(); tv.setText("hello"); tv.setTextSize(30); tv.setTextColor(Color.BLUE);
|
示例:TextViewActivity
activity_text_view.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TextViewActivity"> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="124dp" android:autoLink="web" android:text="https://www.wust.edu.cn" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:autoLink="email" android:text="zhangzhi@wust.edu.cn" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.502" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv1" /> <TextView android:id="@+id/tv3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:autoLink="phone" android:text="+8613012345678" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv2" /> <TextView android:id="@+id/tv4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:autoLink="map" android:text="620 Eighth Avenue New York, NY 10018" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv3" /> <TextView android:id="@+id/tv5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="60dp" android:autoLink="map" android:text="welcome" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.491" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv4" /> <Button android:id="@+id/btn_change" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="修改welcome" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv5" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
TextViewActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class TextViewActivity extends AppCompatActivity { Button btn; TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_text_view); ActionBar actionBar = getSupportActionBar(); actionBar.setTitle("TextView示例"); actionBar.setDisplayHomeAsUpEnabled(true); tv=findViewById(R.id.tv5); btn=findViewById(R.id.btn_change); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { tv.setText("武汉科技大学"); tv.setTextSize(22); tv.setTextColor(Color.BLUE); } }); } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()){ case android.R.id.home: finish(); } return super.onOptionsItemSelected(item); } }
|
2.EditText
常用属性 |
描述 |
hint |
提示信息 |
textColorHint |
提示信息的颜色 |
inputType |
输入类型(number|textPassword|numberPassword … )
|
maxLength |
文本最大长度 |
digits |
允许输入的字符 (如digits=”abcd” 只能输入abcd这4个小写字母) |
多行文本设置 |
|
inputType |
“textMultiLine” //显示多行 |
minLines |
“3” //最小显示3行 |
gravity |
“left|top” // 输入时光标位于左上角 |
inputType 取值不同:会使得输入键盘不同
常用方法
◼ 示例:
1 2 3
| EditText et = (EditText) findViewById(R.id.***); String msg = et.getText().toString(); et.setText("hello");
|
示例:EditTextActivity
activity_edit_text.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".EditTextActivity"> <EditText android:id="@+id/et_phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="32dp" android:ems="10" android:hint="11位手机号" android:inputType="phone" android:maxLength="11" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/et_password" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:ems="10" android:hint="6位密码" android:inputType="numberPassword" android:maxLength="6" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/et_phone" /> <EditText android:id="@+id/et_multitext" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:ems="10" android:hint="个人简介" android:inputType="textMultiLine" android:minLines="3" android:gravity="top|left" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.502" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/et_password" /> <Button android:id="@+id/btn_getdata" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="获取输入值" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/et_multitext" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
EditTextActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class EditTextActivity extends AppCompatActivity { EditText phone; EditText password; EditText info; Button btn; String s_phone; String s_password; String s_info; View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View v) { s_phone = phone.getText().toString(); s_password = password.getText().toString(); s_info = info.getText().toString(); new AlertDialog.Builder(EditTextActivity.this) .setTitle("输入的数据:") .setMessage("电话:" + s_phone + "\n密码:" + s_password + "\n个人简介:\n" + s_info) .setNegativeButton("取消", null) .show(); } }; public void initView() { phone = findViewById(R.id.et_phone); password = findViewById(R.id.et_password); info = findViewById(R.id.et_multitext); btn = findViewById(R.id.btn_getdata); btn.setOnClickListener(listener); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_edit_text); initView(); ActionBar actionBar = getSupportActionBar(); actionBar.setTitle("TextView示例"); actionBar.setDisplayHomeAsUpEnabled(true); } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case android.R.id.home: finish(); } return super.onOptionsItemSelected(item); } }
|
3.ImageView
常用属性 |
描述 |
srcCompat |
图片源 |
scaleType |
图片缩放类型,常用取值:center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY、matrix等
|
scaleType 取值
取值 |
描述 |
fitCenter |
保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满ImageView。缩放后图片居中显示。(默认) |
fitXY |
对X和Y方向独立缩放,直到图片铺满ImageView。这种方式可能会改变图片原本的宽高比,导致图片拉伸变形。 |
fitStart |
保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满ImageView。缩放后图片左上角对齐进行显示。 |
fitEnd |
保持图片的宽高比,对图片进行X和Y方向缩放,直到一个方向铺满ImageView。缩放后图片右下角对齐进行显示。 |
center |
图片居中显示在ImageView中,不对图片进行缩放。 |
centerInside |
如果图片宽度<=ImageView宽度&&图片高度<=ImageView高度,不执行缩放,居中显示在ImageView中。其余情况按ScaleType.FIT_CENTER处理。 |
centerCrop |
保持图片的宽高比,等比例对图片进行X和Y方向缩放,直到每个方向都大于等于ImageView对应的尺寸。缩放后的图片居中显示,超出部分做裁 剪处理。 |
matrix |
使用Matrix绘制图片 |
常用方法
◼ 示例:
1 2 3 4 5 6 7
| ImageView iv = (ImageView) findViewById(R.id.***); iv.setVisibility( View.INVISIBLE ); ❤ 动态加载图片的重要方法: (1) iv.setImageResource(R.drawable.图片资源) (2) iv.setImageDrawable( getDrawable(R.drawable.图片资源) ); (3) iv.setImageURI(Uri uri) / /通过图片URI地址加载图片 (4) iv.setImageBitmap(Bitmap bitmap)
|
示例:ImageViewActivity
定时器用法:Handler.postDelayed(Runnable, long) 方法
定时器基本架构
1 2 3 4 5 6 7 8 9 10 11 12
| Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { handler.postDelayed( this, m ); } };
handler.postDelayed( runnable, n );
handler.removeCallbacks( runnable );
|
注:postDelayed 函数没每次调用只执行一次,所以要使用递归
activity_image_view.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ImageViewActivity"> <ImageView android:id="@+id/iv_photo" android:layout_width="174dp" android:layout_height="180dp" android:layout_marginTop="184dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.496" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/login" /> <Button android:id="@+id/btn_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="53dp" android:text="启动定时器" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/iv_photo" /> <Button android:id="@+id/btn_cancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="关闭定时器" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.501" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/btn_start" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
ImageViewActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class ImageViewActivity extends AppCompatActivity { ImageView imageView; Button btn1, btn2; int idx = 0; int[ ] resIds = new int[ ]{ R.drawable.lstx_001, R.drawable.lstx_002, R.drawable.lstx_003, R.drawable.lstx_004 }; Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { imageView.setImageResource(resIds[idx]); if (idx < resIds.length - 1) { idx++; } else { idx = 0; } handler.postDelayed(this, 2000); } }; View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start: handler.postDelayed(runnable, 2000); break; case R.id.btn_cancel: handler.removeCallbacks(runnable); break; } } }; public void initView() { imageView = findViewById(R.id.iv_photo); btn1 = findViewById(R.id.btn_start); btn2 = findViewById(R.id.btn_cancel); btn1.setOnClickListener(listener); btn2.setOnClickListener(listener); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_image_view); initView(); } }
|
按钮类型 |
描述 |
Button |
普通按钮(仅包含文本) |
ImageButton |
图片按钮(仅包含图标)
◼ srcCompat属性:设置图片源 ◼ scaleType属性:同ImageView ◼ 配合backgroundTint = “#00000000” (8个0) 可以透明png图片背景 ==会导致点击没有波纹效果== ◼ 动态修改图片:setImageDrawable(getDrawable(R.drawable.***)); |
Button组件 |
包含文本和图标按钮
◼ text属性:文本内容 ◼ drawableLeft属性:设置图片源(图片在文字左侧) |
drawableLeft 属性
drawableRight 属性:图片在文字右侧
drawableTop 属性:图片在文字上方
drawableBottom 属性:图片在文字下方
按钮监听器:单击事件响应
1 2 3 4 5 6 7
| Button btn = (Button) findViewById(R.id.***); bt.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { } });
|
禁用按钮方法:
1 2
| btn.setEnabled( false ); btn.setEnabled( true );
|
示例:ButtonActivity
(1) 文字颜色:Button 按下状态改变文字颜色
第 1 步:在 res/drawable/ 目录中新建一个 drawable 资源文件
第 2 步: btn.xml 代码
1 2 3 4 5 6
| <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:color="#ff0" /> <item android:color="#fff" /> </selector>
|
第 3 步: Button 按钮设置
属性 |
值 |
textColor |
@drawable/btn 引用自定义的xml资源 |
注:手工强制添加:android:textColor=”@drawable/btn”
(2) ImageButton:根据按钮状态来更改背景
第 1 步:
先将三种图片复制到 res/drawable/ 目录中
◼ 在 res/drawable/ 目录中新建一个 drawable 资源文件:
第 2 步: button_custom.xml 代码
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable = "@drawable/button_pressed" android:state_pressed = "true" /> <item android:drawable = "@drawable/button_focused" android:state_focused = "true" /> <item android:drawable = "@drawable/button_default" /> </selector>
|
◼ 第一个 <item> 定义按下(激活)按钮后使用的图片
◼ 第二个 <item> 定义按钮处于聚焦状态时(使用方向键突出显示按钮时)使用的图片
◼ 第三个 <item> 定义按钮处于默认状态时(既未按下,也未聚焦时)使用的图片
第 3 步: ImageButton按钮设置
属性 |
值 |
background |
#00000000(8个0,使得png图片背景透明)<- background 透明会让按钮紧密贴合图片 |
srcCompat |
@drawable/button_custom (引用自定义的xml资源) |
activity_button.mxl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ButtonActivity"> <Button android:id="@+id/button" android:layout_width="131dp" android:layout_height="72dp" android:layout_marginTop="92dp" android:text="Button" android:textColor="@drawable/btn" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.135" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageButton android:id="@+id/imageButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="64dp" android:background="#00000000" app:srcCompat="@drawable/button_custom" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.482" app:layout_constraintStart_toEndOf="@+id/button" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
ButtonActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class ButtonActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_button); ActionBar actionBar = getSupportActionBar(); actionBar.setTitle("按钮示例"); actionBar.setDisplayHomeAsUpEnabled(true); } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()){ case android.R.id.home: finish(); } return super.onOptionsItemSelected(item); } }
|
按钮类型 |
描述 |
ToggleButton |
按钮开关,常用属性 textOn、textOff:开、关显示的文字 |
Switch |
滑块开关,常用属性 switchMinWidth:开关最小宽度 |
通用属性:checked |
true:开启,false:关闭 |
开关的监听器:监听开关的状态改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { switch ( buttonView.getId() ) { case R.id.toggleButton: if ( isChecked ) else break; } } };
|
1 2 3 4
| ToggleButton tb = (ToggleButton) findViewById(R.id.toggleButton); Switch sw = (Switch) findViewById(R.id.switch1); tb.setOnCheckedChangeListener(listener); sw.setOnCheckedChangeListener(listener);
|
示例:SwitchActivity
activity_switch.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".SwitchActivity"> <Switch android:id="@+id/switch1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="120dp" android:checked="false" android:switchMinWidth="60dp" android:text="夜间模式" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="88dp" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/switch1" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
SwitchActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class SwitchActivity extends AppCompatActivity { Switch sw; CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { switch ( buttonView.getId() ) { case R.id.switch1: if ( isChecked ) { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); } else { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); } break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_switch); sw = (Switch) findViewById(R.id.switch1); sw.setOnCheckedChangeListener(listener); } }
|
◼ 单选按钮一般归属于某个组(RadioGroup),每组中只能有一个被选中(互斥)
◼ 创建过程:先新建 RadioGroup,然后将 RadioButton 拖放到组中(详见下页)
组件 |
属性描述 |
RadioGroup |
orientation属性:horizontal (水平排列) 或 vertical (垂直排列,默认) |
RadioButton |
text属性:按钮文本,checked属性:是否选中(true表示选中) |
用法示例:先创建 RadioGroup 组件
再创建 RadioButton 组件
RadioButton 的监听器:监听单击事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View view) { boolean checked = ((RadioButton) view).isChecked(); switch( view.getId() ) { case R.id.rb_male: if ( checked ) Toast.makeText(getApplicationContext(),"选中男",Toast.LENGTH_SHORT).show(); break; case R.id.rb_female: if ( checked ) Toast.makeText(getApplicationContext(),"选中女",Toast.LENGTH_SHORT).show(); break; } } };
|
1 2 3 4
| RadioButton rb1 = (RadioButton) findViewById(R.id.rb_male); RadioButton rb2 = (RadioButton) findViewById(R.id.rb_female); rb1.setOnClickListener(listener); rb2.setOnClickListener(listener);
|
RadioGroup的监听器:监听选择状态改变(常用)
1 2 3 4 5 6 7 8
| RadioGroup.OnCheckedChangeListener listener = new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { RadioButton rb = (RadioButton) findViewById(checkedId); String ss = rb.getText().toString(); Toast.makeText(getApplicationContext(), "选中"+ss, Toast.LENGTH_SHORT).show(); } };
|
1 2
| RadioGroup rbg=(RadioGroup)findViewById(R.id.radioGroup); rbg.setOnCheckedChangeListener( listener );
|
示例:RadioActivity
activity_radio.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".RadioActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="32dp" android:layout_marginTop="32dp" android:text="宋朝开国皇帝是哪一位?" android:textSize="20sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <RadioGroup android:id="@+id/radioGroup" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="32dp" android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView"> <RadioButton android:id="@+id/radioButton1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="李渊" android:textSize="20sp" /> <RadioButton android:id="@+id/radioButton2" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="赵匡胤" android:textSize="20sp" /> <RadioButton android:id="@+id/radioButton3" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="朱元璋" android:textSize="20sp" /> <RadioButton android:id="@+id/radioButton4" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="努尔哈赤" android:textSize="20sp" /> </RadioGroup> </androidx.constraintlayout.widget.ConstraintLayout>
|
RadioActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class RadioActivity extends AppCompatActivity { RadioGroup rg; RadioGroup.OnCheckedChangeListener listener=new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { RadioButton rb = findViewById(checkedId); String answer = rb.getText().toString(); if( answer.equals("赵匡胤") ) Toast.makeText(RadioActivity.this,"答对了",Toast.LENGTH_SHORT).show(); else Toast.makeText(RadioActivity.this,"答错了",Toast.LENGTH_SHORT).show(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_radio); rg= findViewById(R.id.radioGroup); rg.setOnCheckedChangeListener(listener); } }
|
7.CheckBox
属性 |
描述 |
text |
按钮文本 |
checked |
是否选中(true为选中) |
CheckBox 的监听器:监听选择状态的改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { switch ( buttonView.getId() ) { case R.id.cb_music: if ( isChecked ) Toast.makeText(getApplicationContext(), "选择音乐", Toast.LENGTH_SHORT).show(); else Toast.makeText(getApplicationContext(), "取消选择音乐", Toast.LENGTH_SHORT).show(); break; case R.id.cb_movie: … } } };
|
1 2 3 4 5 6
| CheckBox cb1 = (CheckBox) findViewById(R.id.cb_music); CheckBox cb2 = (CheckBox) findViewById(R.id.cb_movie); CheckBox cb3 = (CheckBox) findViewById(R.id.cb_sport); cb1.setOnCheckedChangeListener(listener); cb2.setOnCheckedChangeListener(listener); cb3.setOnCheckedChangeListener(listener);
|
示例:CheckBoxActivity 使用 List 存储选中项
activity_check_box.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/constrainLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".CheckBoxActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="44dp" android:layout_marginTop="76dp" android:text="选择爱好" android:textSize="20sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <CheckBox android:id="@+id/cb_music" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="40dp" android:layout_marginTop="120dp" android:text="音乐" android:textSize="20sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <CheckBox android:id="@+id/cb_movie" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="120dp" android:text="电影" android:textSize="20sp" app:layout_constraintStart_toEndOf="@+id/cb_music" app:layout_constraintTop_toTopOf="parent" /> <CheckBox android:id="@+id/cb_sport" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="120dp" android:text="体育" android:textSize="20sp" app:layout_constraintStart_toEndOf="@+id/cb_movie" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
CheckBoxActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class CheckBoxActivity extends AppCompatActivity { private List<String> list = new ArrayList<>(); CompoundButton.OnCheckedChangeListener listener = new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if ( isChecked ) list.add( buttonView.getText().toString() ); else list.remove( buttonView.getText().toString() ); Log.d("flag", list.toString()); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_check_box); CheckBox cb1 = (CheckBox) findViewById(R.id.cb_music); CheckBox cb2 = (CheckBox) findViewById(R.id.cb_movie); CheckBox cb3 = (CheckBox) findViewById(R.id.cb_sport); cb1.setOnCheckedChangeListener(listener); cb2.setOnCheckedChangeListener(listener); cb3.setOnCheckedChangeListener(listener); } }
|
8.SeekBar
属性/方法 |
描述 |
min |
滑动条的最小值(一般设置为 0) |
max |
滑动条的最大值(如 100) |
setMin(int) |
设置滑动条的最小值 |
setMax(int) |
设置滑动条的最大值 |
progress |
滑动条的当前值(如初始设置为50) |
setProgress(int) |
设置滑动条当前值 |
getProgress() |
返回滑动条当前值 |
thumb |
滑块的drawable(如设置滑块图片)
|
SeekBar 监听器:监听滑块进度变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } });
|
示例:SeekBarActivity
activity_seek_bar.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".SeekBarActivity"> <TextView android:id="@+id/seekbarvalue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:text="1×" android:textSize="16sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <SeekBar android:id="@+id/seekBar2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="24dp" android:layout_marginTop="80dp" android:layout_marginEnd="24dp" android:max="20" android:min="0" android:progress="10" android:thumb="@drawable/twitter" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
<ImageView android:id="@+id/photo2" android:layout_width="285dp" android:layout_height="371dp" android:layout_marginTop="32dp" android:scaleType="matrix" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/seekBar2" app:srcCompat="@drawable/alert" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
SeekBarActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class SeekBarActivity extends AppCompatActivity { SeekBar seekBar; TextView seekBarValue; ImageView imageView; Matrix matrix = new Matrix(); public void scale(float sx,float sy) { matrix.set( imageView.getImageMatrix() ); int x = imageView.getDrawable().getBounds().centerX(); int y = imageView.getDrawable().getBounds().centerY(); matrix.setScale( sx, sy , x, y ); imageView.setImageMatrix( matrix ); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_seek_bar); seekBar = (SeekBar) findViewById(R.id.seekBar2); seekBarValue = (TextView) findViewById(R.id.seekbarvalue); imageView = findViewById(R.id.photo2); imageView.setScaleType(ImageView.ScaleType.MATRIX); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { seekBarValue.setText( progress/10.0f + "×" ); scale( progress/10.0f, progress/10.0f ); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } }
|
9.Spinner
常用属性和方法 |
描述 |
entries属性 |
选项的数据来源(静态填充数据) |
getSelectedItem() |
获取选中项(注:使用toString()转为字符串) |
getItemAtPosition(int) |
根据位置选择某项(注:使用toString()转为字符串) |
说明:默认情况下 Spinner 字体/颜色等不能直接设置,需自定义布局
Spinner 数据填充:静态填充
(1)先在 res/values/strings.xml 文件中声明字符串数组
1 2 3 4 5 6
| <string-array name="major_array"> <item>软件工程</item> <item>计算机科学</item> <item>网络工程</item> <item>信息安全</item> </string-array>
|
(2)Spinner的entries属性设置为:@array/major_array ==静态引用==
Spinner 数据填充:动态填充(常用)
1 2 3 4 5 6 7 8 9 10 11
| List<String> list = new ArrayList<String>();
list.add("软件工程"); list.add("计算机科学"); list.add("网络工程"); list.add("信息安全");
ArrayAdapter<String> adapter = new ArrayAdapter<String>( 当前Activity.this, android.R.layout.simple_list_item_1, list );
Spinner spinner = (Spinner)findViewById(R.id.spinner的id); spinner.setAdapter(adapter);
|
系统内置的常见布局:
android.R.layout.布局id |
描述 |
simple_list_item_1 |
每个列表项是一个普通的文字 |
simple_list_item_2 |
每个列表项是两个文本(一主一副) -> |
simple_list_item_checked |
每个列表项会有一个选中项 |
simple_list_item_single_choice |
每个列表项后面会有一个radio按钮 |
simple_list_item_multiple_choice |
每个列表项后面会有一个checkbox按钮 |
什么是 Adapter
◼ Adapter:称为”适配器”,是用来帮助 UI 组件填充数据的中间桥梁。(也是一种 MVC 体系结构)
常见的 Adapter:
◼ BaseAdapter:是一个抽象类,继承它需要实现较多的方法,所以也就具有较高的灵活性。
◼ ArrayAdapter:支持泛型操作,最为简单,只能展示一行字。
◼ SimpleAdapter:有很好的扩充性,可以自定义出各种效果。
◼ SimpleCursorAdapter:与数据库的简单结合,可以方便地把数据库的内容以列表的形式展示出来。
使用自定义布局:详见示例1
1 2 3 4 5 6 7 8 9 10
| List<String> list = new ArrayList<String>(); list.add("软件工程"); list.add("计算机科学"); list.add("网络工程"); list.add("信息安全");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(当前Activity.this, R.layout.spinner_custom, R.id.tv_item, list); Spinner spinner = (Spinner)findViewById(R.id.spinner的id); spinner.setAdapter(adapter);
|
Spinner 监听器:监听选中项的变化
1 2 3 4 5 6 7 8 9 10 11
| spinner.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { } @Override public void onNothingSelected(AdapterView<?> parent) { } });
|
其中 onItemSelected 函数四个参数含义:
◼ parent:指 Spinner 对象
◼ view:选中项的视图对象
◼ position:选中项的位置值
◼ id:选中项的行 id 值(从 0 开始)
注:一般情况 position 和 id 值一样
注:Spinner 不要用 setOnItemClickListener 监听器,会闪退
示例1:Spinner1Activity
界面布局代码:activity_spinner1.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".Spinner1Activity"> <TextView android:id="@+id/tv_major" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="52dp" android:layout_marginTop="104dp" android:text="专业选择:" android:textColor="@color/purple_500" android:textSize="18sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Spinner android:id="@+id/sp_major" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginStart="52dp" android:layout_marginTop="12dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_major" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
Spinner1Activity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class Spinner1Activity extends AppCompatActivity { Spinner sp_major; TextView tv_major; List<String> list; ArrayAdapter<String> adapter; AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { tv_major.setText("专业选择:" + parent.getSelectedItem()); } @Override public void onNothingSelected(AdapterView<?> parent) { } }; public void initView(){ tv_major=findViewById(R.id.tv_major); sp_major=findViewById(R.id.sp_major); sp_major.setOnItemSelectedListener(listener); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_spinner1); initView(); list = new ArrayList<String>(); list.add("软件工程"); list.add("计算机科学"); list.add("网络工程");
adapter = new ArrayAdapter<String>( Spinner1Activity.this,R.layout.spinner_custom, R.id.tv_item, list ); sp_major.setAdapter(adapter); } }
|
自定义布局:在 res/layout 中新建布局资源文件
自定义布局的设计:
自定义布局的代码:sipnner_custom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/spinner_custom" android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="1dp" android:layout_marginTop="1dp" android:layout_marginEnd="1dp" android:orientation="horizontal" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent">
<TextView android:id="@+id/tv_item" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_weight="1" android:gravity="center_vertical" android:text="item内容" android:textColor="@android:color/holo_green_dark" android:textSize="20sp" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
|
示例2:Spinner2Activity
界面布局代码:activity_spinner2.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/constrainLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".Spinner2Activity"> <Spinner android:id="@+id/sp_province" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginStart="1dp" android:layout_marginTop="80dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Spinner android:id="@+id/sp_city" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="80dp" app:layout_constraintStart_toEndOf="@+id/sp_province" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
Spinner2Activity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| public class Spinner2Activity extends AppCompatActivity { Spinner sp_province; Spinner sp_city; List<String> provinceList = new ArrayList<String>( Arrays.asList("选择省","湖北省","湖南省") ); List<String> cityList = new ArrayList<String>( Arrays.asList("选择市") ); ArrayAdapter<String> adapter; public void setAdapter( Spinner spinner, List<String> list ) { adapter = new ArrayAdapter<String>( Spinner2Activity.this, android.R.layout.simple_list_item_1, list ); spinner.setAdapter(adapter); } public void initView() { sp_province = (Spinner)findViewById(R.id.sp_province); sp_city = (Spinner)findViewById(R.id.sp_city); setAdapter(sp_province,provinceList); setAdapter(sp_city,cityList); sp_province.setOnItemSelectedListener( listener ); }
private AdapterView.OnItemSelectedListener listener=new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if ( parent.getId() == R.id.sp_province ) { String pName = parent.getSelectedItem().toString(); switch (pName) { case "选择省": cityList.clear(); cityList.add("选择市"); break; case "湖北省": cityList.clear(); cityList.add("武汉"); cityList.add("宜昌"); break; case "湖南省": cityList.clear(); cityList.add("长沙"); cityList.add("湘潭"); break; } setAdapter(sp_city, cityList); sp_city.setOnItemSelectedListener(listener); } else if ( parent.getId() == R.id.sp_city ) { Toast.makeText(Spinner2Activity.this, "选中的是:" + sp_province.getSelectedItem() + sp_city.getSelectedItem(), Toast.LENGTH_SHORT).show(); } } @Override public void onNothingSelected(AdapterView<?> parent) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_spinner2); initView(); } }
|
10.ListView
常用属性和方法 |
描述 |
entries属性 |
选项的数据来源(静态填充) |
setChoiceMode(int) |
设置选中模式 ◼ 多选:ListView.CHOICE_MODE_MULTIPLE ◼ 单选:ListView.CHOICE_MODE_SINGLE(默认) |
getItemAtPosition(int) |
根据位置选择某项,使用toString()转为字符串 |
getCount() |
获得选项总数 |
getCheckedItemCount() |
获得选中个数 |
setSelector(资源id) |
设置高亮选中项的背景色或图片 |
常用布局配合选中模式
ListView数据动态填充:以多选为例
1 2 3 4 5 6 7 8 9 10 11
| List<String> list = new ArrayList<String>(); list.add("Java"); list.add("C"); list.add("Python"); ArrayAdapter<String> adapter = new ArrayAdapter<String>( MainActivity.this, android.R.layout.simple_list_item_multiple_choice, list ); ListView listView = (ListView)findViewById(R.id.listView); listView.setAdapter(adapter); listView.setChoiceMode( ListView.CHOICE_MODE_MULTIPLE );
|
ListView 监听器:监听选项单击事件,以多选为例
1 2 3 4 5 6 7 8 9 10 11 12
| listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ListView lv = (ListView)parent; if ( ((CheckedTextView) view).isChecked() ) else } });
|
onItemClick 函数的四个参数含义:
◼ parent:指 ListView 对象
◼ view:击中项的视图对象
◼ position:击中项的位置值
◼ id:击中项的行 id 值(从 0 开始)
注:一般情况 position 和 id 值一样
注:ListView不使用OnItemSelectedListener (Spinner才用)
示例:ListViewActivity
activity_list_view.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ListViewActivity"> <TextView android:id="@+id/tv_skill" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="选择擅长的技术" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ListView android:id="@+id/lv_skill" android:layout_width="match_parent" android:layout_height="200dp" android:layout_marginTop="8dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_skill" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
ListViewActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class ListViewActivity extends AppCompatActivity { ListView listView; ArrayAdapter<String> adapter; List<String> skill_list = new ArrayList<>(Arrays.asList("Java", "C", "Python")); List<String> selected_list = new ArrayList<>(); public void initView() { listView = findViewById(R.id.lv_skill); adapter= new ArrayAdapter<String>( ListViewActivity.this, android.R.layout.simple_list_item_multiple_choice, skill_list); listView.setAdapter(adapter); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); listView.setOnItemClickListener(listener); } AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ListView lv = (ListView) parent; if ( ((CheckedTextView) view).isChecked() ) { selected_list.add(lv.getItemAtPosition(position).toString()); } else { selected_list.remove(lv.getItemAtPosition(position).toString()); } Log.d("flag", selected_list.toString()); Log.d("flag", "一共选中" + lv.getCheckedItemCount() + "/" + lv.getCount()); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list_view); initView(); } }
|
11.AutoCompleteTextView
常用属性 |
描述 |
completionHint |
设置下拉菜单中的提示标题 |
completionThreshold |
指定用户至少输入多少个字符才会显示提示 |
singleLine |
true为单行,false为多行(默认) |
用法示例:动态填充
1 2 3 4 5 6 7
| List<String> data = new ArrayList<>(Arrays.asList("Apple", "AMD", "Acer", "Intel", "Microsoft")); AutoCompleteTextView auto = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(当前Activity.this, android.R.layout.simple_dropdown_item_1line, data); auto.setThreshold(1); auto.setCompletionHint("提示信息"); auto.setAdapter(adapter);
|
示例:AutoCompleteActivity
activity_auto_complete.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".AutoCompleteActivity"> <AutoCompleteTextView android:id="@+id/autoCompleteTextView" android:layout_width="250dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="60dp" android:hint="输入公司名" android:singleLine="true" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/btn_search" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="32dp" android:layout_marginTop="60dp" android:backgroundTint="@android:color/holo_green_light" android:text="搜索" android:textSize="20sp" app:layout_constraintStart_toEndOf="@+id/autoCompleteTextView" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
AutoCompleteActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class AutoCompleteActivity extends AppCompatActivity { AutoCompleteTextView auto; Button btn; List<String> data = new ArrayList<>(Arrays.asList("Apple", "AMD", "Acer", "Intel", "Microsoft")); ArrayAdapter<String> adapter; View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View v) { String input = auto.getText().toString(); if( data.contains(input) ){ Toast.makeText(AutoCompleteActivity.this,"查询中...",Toast.LENGTH_SHORT).show(); }else{ data.add(input); adapter.add(input); adapter.notifyDataSetChanged(); Toast.makeText(AutoCompleteActivity.this,"已添加",Toast.LENGTH_SHORT).show(); } } }; public void initView() { btn = findViewById(R.id.btn_search); btn.setOnClickListener(listener); auto = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView); adapter = new ArrayAdapter<String>(AutoCompleteActivity.this, android.R.layout.simple_dropdown_item_1line, data); auto.setThreshold(1); auto.setCompletionHint("公司名称"); auto.setAdapter(adapter); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_auto_complete); initView(); } }
|
12.DatePicker和TimePicker
UI 组件代码
注:需手工输入代码
1 2 3 4 5 6 7 8 9 10 11 12
| <DatePicker android:id="@+id/datePicker" android:layout_width="wrap_content" android:layout_height="wrap_content"> </DatePicker>
<TimePicker android:id="@+id/timePicker" android:layout_width="wrap_content" android:layout_height="wrap_content"> </TimePicker>
|
DatePicker 监听器:监听日期改变
1 2 3 4 5 6 7
| DatePicker datePicker=(DatePicker) findViewById(R.id.datePicker); datePicker.setOnDateChangedListener(new DatePicker.OnDateChangedListener() { @Override public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) { } });
|
日期和时间选择对话框(常用)
日期选择对话框:
1 2 3 4 5 6 7 8
| Calendar data = Calendar.getInstance(); DatePickerDialog dpd = new DatePickerDialog( 当前Activity.this, new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int month, int day) { } }, data.get(Calendar.YEAR), data.get(Calendar.MONTH), data.get(Calendar.DAY_OF_MONTH) ); dpd.show();
|
时间选择对话框:
1 2 3 4 5 6 7 8
| Calendar data = Calendar.getInstance(); TimePickerDialog tpd = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { } }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true); tpd.show();
|
示例:日期和时间选择对话框
重要:EditText 单击触发 onclick 事件处理
◼ 默认情况下:EditText 单击只能获得焦点,并不触发 onclick 事件
◼ 如果要直接触发 onclick 事件,EditText 添加两个属性
• android:clickable = "true"
//允许单击
• android:focusableInTouchMode="false"
//不获得焦点,此时会触发 onclick 事件
activity_date_time_picker.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".DateTimePickerActivity"> <EditText android:id="@+id/et_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:ems="10" android:hint="输入日期" android:inputType="textPersonName" android:clickable="true" android:focusableInTouchMode="false" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/et_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="100dp" android:ems="10" android:hint="输入时间" android:inputType="textPersonName" android:textSize="20sp" android:clickable="true" android:focusableInTouchMode="false" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
DateTimePickerActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| public class DateTimePickerActivity extends AppCompatActivity { EditText et_date, et_time; public void initView() { et_date = findViewById(R.id.et_date); et_time = findViewById(R.id.et_time); et_date.setOnClickListener(listener); et_time.setOnClickListener(listener); } View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.et_date: getDate(); break; case R.id.et_time: getTime(); break; } } };
public void getDate() { Calendar data = Calendar.getInstance(); DatePickerDialog dpd = new DatePickerDialog(DateTimePickerActivity.this, new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int month, int day) { String str; str = String.valueOf(year) + "-" + String.valueOf(month+1) + "-" + String.valueOf(day); et_date.setText(str); } }, data.get(Calendar.YEAR), data.get(Calendar.MONTH), data.get(Calendar.DAY_OF_MONTH)); dpd.show(); }
public void getTime() { Calendar calendar = Calendar.getInstance(); TimePickerDialog tpd = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { String str; str = String.valueOf(hourOfDay) + ":" + String.valueOf(minute) ; et_time.setText(str); } }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true); tpd.show(); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_date_time_picker); initView(); } }
|
编程示例
模拟登录
基本步骤: app全屏显示
◼ Activity主题和配置
◼ Activity全屏
◼ 界面布局设计
◼ 按钮文字颜色(详见5.2节)
◼ UI编程
1.Activity 主题和配置
◼ 新建Activity: LoginActivity
◼ 在 themes.xml 中添加新主题:
1 2 3 4 5 6 7
| <style name="Theme.Login" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <item name="colorPrimary">@android:color/holo_orange_dark</item> <item name="colorPrimaryVariant">@color/purple_700</item> <item name="colorOnPrimary">@color/white</item> <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> </style>
|
修改 Activity 配置
◼ 在 AndroidManifest.xml 修改 LoginActivity 配置:
1 2 3 4 5 6 7 8 9 10 11
| <activity android:name=".LoginActivity" android:exported="true" android:icon="@drawable/login" android:label="用户登录" android:theme="@style/Theme.Login"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
|
运行APP:观察主题效果
2.Activity全屏
◼ LoginActivity 添加代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class LoginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); } @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch ( item.getItemId() ) { case android.R.id.home: finish(); } return super.onOptionsItemSelected(item); } }
|
运行结果:
3.界面布局设计
布局设计:ImageView 组件
布局设计:TextView组件(手机号标签)
布局设计:EditText组件(手机号文本框)
布局设计:TextView组件(密码标签)
布局设计:EditText组件(密码框)
布局设计:Button组件(登录按钮)
最终布局代码:activity_login.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".LoginActivity"> <ImageView android:id="@+id/photo" android:layout_width="165dp" android:layout_height="177dp" android:layout_marginStart="16dp" android:layout_marginTop="32dp" android:layout_marginEnd="16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/login" /> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="24dp" android:layout_marginTop="50dp" android:text="手机号" android:textSize="24sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/photo" /> <EditText android:id="@+id/phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:ems="10" android:hint="11位手机号" android:inputType="phone" android:maxLength="11" android:textSize="24sp" app:layout_constraintBaseline_toBaselineOf="@+id/textView1" app:layout_constraintStart_toEndOf="@+id/textView1" />
<TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="24dp" android:layout_marginTop="25dp" android:text="密 码" android:textSize="24sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView1" />
<EditText android:id="@+id/password" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="12dp" android:ems="10" android:hint="不超过10个字符" android:inputType="textPassword" android:maxLength="10" android:textSize="24sp" app:layout_constraintBaseline_toBaselineOf="@+id/textView2" app:layout_constraintStart_toEndOf="@+id/textView2" />
<Button android:id="@+id/login_btn" android:layout_width="379dp" android:layout_height="66dp" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:layout_marginBottom="36dp" android:backgroundTint="@android:color/holo_green_light" android:text="登录" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
|
运行结果:
4.UI编程
获取输入的数据(LoginActivity代码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| private EditText phone; private EditText password; private Button login;
private String s_phone; private String s_password;
View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View view) login(); } };
public void init() { phone = (EditText) findViewById(R.id.phone); password = (EditText) findViewById(R.id.password); login = (Button) findViewById(R.id.login_btn); login.setOnClickListener(listener); } public void login() { s_phone = phone.getText().toString(); s_password = password.getText().toString(); String msg = "手机号=" + s_phone + ",密码=" + s_password; Log.d("flag", msg); Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); … init(); }
|
模拟验证码重发(10秒倒计时)
倒计时CountDownTimer用法
1 2 3 4 5 6 7 8 9 10 11
| CountDownTimer countDownTimer = new CountDownTimer(参数1, 参数2) { @Override public void onTick(long millisUntilFinished) { … } @Override public void onFinish() { … } };
|
◼ 启动倒计时:countDownTimer.start();
◼ 取消倒计时:countDownTimer.cancel();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class LoginActivity extends AppCompatActivity { …. private Button btn_send; public void init() { … btn_send = (Button)findViewById( R.id.btn_send ); btn_send.setOnClickListener( listener ); } CountDownTimer countDownTimer = new CountDownTimer(10000, 1000) { @Override public void onTick(long millisUntilFinished) { btn_send.setText( millisUntilFinished / 1000 +"秒后可重发" ); } @Override public void onFinish() { btn_send.setEnabled(true); btn_send.setText("发送验证码"); } }; View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View view) { switch (view.getId()){ case R.id.login_btn: login(); break; case R.id.btn_send: btn_send.setEnabled(false); countDownTimer.start(); break; } } }; … }
|
图片查看
◼ 新建 Activity: PicShowActivity
图片准备:本例图片文件存放在 assets 文件夹中
◼ assets 文件夹:
◼ 可以存放如图片、音频、视频等资源
◼ 该目录下的文件在打包后会原封不动的保存在 apk 包中,不会被编译成二进制
◼ assets 可以有目录结构,也就是 assets 目录下可以再建立文件夹
◼ 注意:
◼ assets 文件夹下的文件不会被映射到 R.java 中,访问的时候需要 AssetManager 类
assets文件读取方法:
◼ 读取 assets 下的文件资源:
1 2
| String[] fNames = getAssets().list("pic"); InputStream is = getAssets().open("filename");
|
新建 assets 目录
◼ 项目右键→New → Folder → Assets Folder
在assets目录中新建子目录:
◼ assets目录右键 → New → Directory
将图片资源复制到 assets/pic 下
activity_pic_show.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".PicShowActivity"> <TextView android:id="@+id/tv_pic" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="选择图片查看" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ListView android:id="@+id/lv_pic" android:layout_width="match_parent" android:layout_height="300dp" android:layout_marginTop="8dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_pic" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| public class PicShowActivity extends AppCompatActivity { ListView listView; ArrayAdapter<String> adapter; List<String> pic_list = new ArrayList<>(); public void initView() { listView = findViewById(R.id.lv_pic); pic_list = getPic(); adapter = new ArrayAdapter<String>( PicShowActivity.this, android.R.layout.simple_list_item_single_choice, pic_list); listView.setAdapter(adapter); listView.setChoiceMode( ListView.CHOICE_MODE_SINGLE ); listView.setOnItemClickListener(listener); } public List<String> getPic() { List<String> pList = new ArrayList<>(); try { String[] fNames = getAssets().list("pic"); for (String fn : fNames) { pList.add(fn); } } catch (IOException e) { throw new RuntimeException(e); } return pList; }
AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ListView lv = (ListView) parent; lv.setSelector(R.color.purple_200); String pName = parent.getItemAtPosition(position).toString(); showPic(pName); } };
public void showPic(String pName) { try { InputStream is = getAssets().open("pic/" + pName); Bitmap bitmap = BitmapFactory.decodeStream(is); final Dialog dialog = new Dialog(PicShowActivity.this, android.R.style.Theme_Black_NoTitleBar_Fullscreen); ImageView imgView = getView(bitmap); dialog.setContentView(imgView); dialog.show(); imgView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); } catch (IOException e) { throw new RuntimeException(e); } }
private ImageView getView(Bitmap bitmap) { ImageView iv = new ImageView( PicShowActivity.this ); iv.setLayoutParams(new ActionBar.LayoutParams( ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT)); iv.setImageBitmap(bitmap); return iv; }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pic_show); initView(); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); ActionBar actionBar = getSupportActionBar(); actionBar.setTitle("图片查看示例"); actionBar.setDisplayHomeAsUpEnabled(true); } }
|
音乐播放器
ExoPlayer+SeekBar+定时器
◼ 新建 Activity: MusicActivity
音乐准备:本例音乐放在 res/raw 目录下
◼ 在 res 中新建 raw 资源文件夹,然后将音乐(例如she.mp3)复制到 raw 文件夹
了解:asset 和 res/raw 文件夹区别
◼ 相同点:
◼ asset 和 res/raw 文件夹下都可以存放如音频、视频等资源
◼ 两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制
◼ 不同点:
◼ res/raw 中的文件会被映射到 R.java 文件中,访问的时候直接使用资源 ID,即 R.raw.资源id;
◼ assets 文件夹下的文件不会被映射到 R.java 中,访问的时候需要 AssetManager 类
◼ res/raw 不可以有目录结构,而 assets 则可以有目录结构,也就是 assets 目录下可以再建立文件夹
文件读取的区别
◼ 读取 res/raw 下的文件资源:
1
| InputStream is = getResources().openRawResource( R.raw.资源id );
|
◼ 读取 assets 下的文件资源:
1 2
| String[] fNames = getAssets().list("music"); InputStream is = getAssets().open("filename");
|
关于:ExoPlayer 媒体播放器
◼ Google 推出的开源媒体播放器 (可取代 MediaPlayer)
◼ 支持本地音视频的播放,同时也支持网络视频播放
◼ 使用前需要添加依赖:如下:
添加 ExoPlayer 依赖
媒体播放器常用方法
方法 |
描述 |
创建ExoPlayer对象 |
ExoPlayer player = new ExoPlayer.Builder( MusicActivity.this ).build(); |
setMediaItem() |
添加媒体(支持本地和远程资源) |
prepare() |
在播放前调用此方法完成播放准备工作 |
start() |
开始或继续播放媒体 |
pause() |
暂停播放 |
stop() |
停止播放 |
release() |
释放播放器对象相关资源 |
isPlaying() |
判断当前播放器是否正在播放 |
seekTo() |
从指定位置开始播放 |
getDuration() |
获取媒体文件的时长(毫秒) |
getContentPosition() |
获取媒体播放的当前位置(毫秒) |
addListener() |
添加监听器(如onPlaybackStateChanged播放状态监听等,比较多) |
setRepeatMode() |
设置循环播放模式:ExoPlayer.REPEAT_MODE_ONE 单曲循环 ExoPlayer.REPEAT_MODE_ALL 全部循环 |
activity_music.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/constrainLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MusicActivity"> <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="100dp" android:layout_marginEnd="8dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageButton android:id="@+id/btn_player" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="64dp" android:backgroundTint="@android:color/holo_orange_light" android:scaleType="fitCenter" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/seekBar" app:srcCompat="@android:drawable/ic_media_play" /> <TextView android:id="@+id/seekBarHint" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="当前进度" android:textSize="18sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/seekBar" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
MusicActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| public class MusicActivity extends AppCompatActivity { SeekBar seekBar; TextView seekBarHint; ImageButton btn_player; ExoPlayer player; private Timer timer; private boolean prepared; private class ProgressUpdate extends TimerTask { @Override public void run() { runOnUiThread( new Runnable() { @Override public void run() { long position = player.getContentPosition(); Log.d("flag", "pos=" + position); seekBar.setProgress((int) position); seekBarHint.setText( format(position) ); } }); } } public String format(long position) { SimpleDateFormat sdf = new SimpleDateFormat("mm:ss"); String timeStr = sdf.format(position); return timeStr; } public void initView(){ btn_player = (ImageButton) findViewById(R.id.btn_player); seekBar = (SeekBar) findViewById(R.id.seekBar); seekBarHint = (TextView) findViewById(R.id.seekBarHint); }
public void initExoPlayer() { player = new ExoPlayer.Builder(MusicActivity.this).build(); MediaItem mediaItem = MediaItem.fromUri( RawResourceDataSource.buildRawResourceUri( R.raw.she )); player.setMediaItem(mediaItem); player.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE); player.prepare(); } Player.Listener listener1 = new Player.Listener() { @Override public void onPlaybackStateChanged(int playbackState) { if (playbackState == ExoPlayer.STATE_READY) { prepared = true; long realDurationMillis = player.getDuration(); seekBar.setMax((int) realDurationMillis); } } }; View.OnClickListener listener2 = new View.OnClickListener() { @Override public void onClick(View v) { if ( !prepared ) return; if ( player.isPlaying() ) { player.pause(); btn_player.setImageResource(android.R.drawable.ic_media_play); timer.cancel(); timer = new Timer(); } else { player.play(); btn_player.setImageResource(android.R.drawable.ic_media_pause); timer = new Timer(); timer.schedule(new ProgressUpdate(), 300, 500); } } }; SeekBar.OnSeekBarChangeListener listener3 = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (prepared && fromUser) { player.seekTo(progress); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { seekBarHint.setText(format(seekBar.getProgress())); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_music); initView(); prepared = false; initExoPlayer();
player.addListener(listener1); btn_player.setOnClickListener(listener2); seekBar.setOnSeekBarChangeListener(listener3); } @Override protected void onDestroy() { super.onDestroy(); player.stop(); player.release(); } }
|
Activity间的跳转
在 Android 中,Activity 跳转是指从一个 Activity 转到另一个 Activity 的过程。可以通过 Intent 来实现 Activity 之间的跳转。一般情况下,使用startActivity() 方法来启动一个新的 Activity,也可以使用 startActivityForResult() 方法来启动一个新的 Activity 并返回结果。在跳转时,需要指定目标 Activity 的类名或 Intent 对象。同时,也可以在 Intent 中传递参数,以便在目标 Activity 中使用。
下面给出一个通过 Intent 来实现 Activity 间跳转的案例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class TestActivity extends AppCompatActivity { private Intent intent2;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test);
intent2=new Intent(); intent2.setComponent(new ComponentName(TestActivity.this, LoginActivity.class));
startActivity(intent2); } }
|
一个用于跳转到多个 Activity 的案例
activity_test.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TextViewActivity"> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="124dp" android:autoLink="web" android:text="https://www.wust.edu.cn" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:autoLink="email" android:text="zhangzhi@wust.edu.cn" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.502" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv1" /> <TextView android:id="@+id/tv3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:autoLink="phone" android:text="+8613012345678" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv2" /> <TextView android:id="@+id/tv4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:autoLink="map" android:text="620 Eighth Avenue New York, NY 10018" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv3" /> <TextView android:id="@+id/tv5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="60dp" android:autoLink="map" android:text="welcome" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.491" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv4" /> <Button android:id="@+id/btn_change" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="修改welcome" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv5" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
TestActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
| public class TestActivity extends AppCompatActivity {
class BtnClickListener implements View.OnClickListener { @Override public void onClick(View v) { switch (v.getId()) { case R.id.activity_auto_complete: Intent intent0 = new Intent(TestActivity.this, AutoCompleteActivity.class); startActivity(intent0); break; case R.id.activity_button: Intent intent1 = new Intent(TestActivity.this, ButtonActivity.class); startActivity(intent1); break; case R.id.activity_check_box: Intent intent2 = new Intent(TestActivity.this, CheckBoxActivity.class); startActivity(intent2); break; case R.id.activity_date_time_picker: Intent intent3 = new Intent(TestActivity.this, DateTimePickerActivity.class); startActivity(intent3); break; case R.id.activity_edit_text: Intent intent4 = new Intent(TestActivity.this, EditTextActivity.class); startActivity(intent4); break; case R.id.activity_image_view: Intent intent5 = new Intent(TestActivity.this, ImageViewActivity.class); startActivity(intent5); break; case R.id.activity_list_view: Intent intent6 = new Intent(TestActivity.this, ListViewActivity.class); startActivity(intent6); break; case R.id.activity_login: Intent intent7 = new Intent(TestActivity.this, LoginActivity.class); startActivity(intent7); break; case R.id.activity_music: Intent intent8 = new Intent(TestActivity.this, MusicActivity.class); startActivity(intent8); break; case R.id.activity_pic_show: Intent intent9 = new Intent(TestActivity.this, PicShowActivity.class); startActivity(intent9); break; case R.id.activity_radio: Intent intent10 = new Intent(TestActivity.this, RadioActivity.class); startActivity(intent10); break; case R.id.activity_seek_bar: Intent intent11 = new Intent(TestActivity.this, SeekBarActivity.class); startActivity(intent11); break; case R.id.activity_spinner1: Intent intent12 = new Intent(TestActivity.this, Spinner1Activity.class); startActivity(intent12); break; case R.id.activity_spinner2: Intent intent13 = new Intent(TestActivity.this, Spinner2Activity.class); startActivity(intent13); break; case R.id.activity_switch: Intent intent14 = new Intent(TestActivity.this, SwitchActivity.class); startActivity(intent14); break; } } }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test);
BtnClickListener btnClickListener = new BtnClickListener();
findViewById(R.id.activity_auto_complete).setOnClickListener(btnClickListener);
findViewById(R.id.activity_button).setOnClickListener(btnClickListener);
findViewById(R.id.activity_check_box).setOnClickListener(btnClickListener);
findViewById(R.id.activity_date_time_picker).setOnClickListener(btnClickListener);
findViewById(R.id.activity_edit_text).setOnClickListener(btnClickListener);
findViewById(R.id.activity_image_view).setOnClickListener(btnClickListener);
findViewById(R.id.activity_list_view).setOnClickListener(btnClickListener);
findViewById(R.id.activity_login).setOnClickListener(btnClickListener);
findViewById(R.id.activity_music).setOnClickListener(btnClickListener);
findViewById(R.id.activity_pic_show).setOnClickListener(btnClickListener);
findViewById(R.id.activity_radio).setOnClickListener(btnClickListener);
findViewById(R.id.activity_seek_bar).setOnClickListener(btnClickListener);
findViewById(R.id.activity_spinner1).setOnClickListener(btnClickListener);
findViewById(R.id.activity_spinner2).setOnClickListener(btnClickListener);
findViewById(R.id.activity_switch).setOnClickListener(btnClickListener); } }
|