UI组件:
一、Toast:显示提示信息
1、显示文件内容:
Toast.makeText(context,"文本内容",时间).show();
时间:Toast.LENGTH_LONG 时间长一点
Toast.LENGTH_SHORT 时间短一点
Context:表示上下文对象,可以表示整个应用程序的上下文对象(应用程序级全局对象),也可以表示
一个界面的上下文对象(Activity)
2、显示图片
Toast t = new Toast(this); //创建Toast对象
ImageView view = new ImageView(this); //创建一个图片组件
view.setImageResource(R.mipmap.ic_launcher); //为图片组件设置图片资源
t.setView(view); //把图片组件设置到Toast组件上
t.setDuration(Toast.LENGTH_LONG);//设置显示的时间
t.show();//显示
3、显示图文
<1>创建 一个布局对象,用于组合多个组件,比如(LinearLayout)
<2>设置布局组件的相关属性(比如方向,内部组件显示的相对位置)
<3>创建需要添加到布局组件中的组件对象(ImageView 和 TextView)
<4>分别为组件对象设置内容(图片组件设置图片资源,文本组件设置文本内容)
<5>通过addView(...)方法把组件添加到布局组件中
<6>再把布局组件添加到Toast上,显示
通过这个示例,我们了解如何通过代码的方式组合组件,再显示到界面上
二、TextView组件
常用的属性设置:
android:textIsSelectable="true" 设置文本内容可选(触发系统的复制粘贴功能)
android:drawableLeft="@mipmap/ic_launcher" 设置文本内容的图标
其它包括drawableRight, drawableTop, drawableBottom, drawableStart, drawableEnd
android:text="Hello World!" 设置显示的文本内容
android:textColor="@color/colorAccent" 设置文本颜色
android:textSize="24sp" 设置文本字体大小
android:textStyle="bold" 设置字体的样式(bold 粗体,normal 默认, italic 斜体)
android:clickable="true" 是否可以单击
android:onClick="" 可单击的情况下,可以设置单击事件
android:ellipsize="marquee" 设置文本内容超出显示范围的显示方式
end, marquee, middle, none, start
android:lines="1" 设置显示的行数
android:maxLines="1" 最大的行数
android:minLines="1" 最小的行数
android:gravity 设置文本内容的位置
android:background="@color/colorPrimary" 设置背景颜色
三、EditText输入组件,是TextView的子类
用于接收输入文本内容
常用的属性:
android:hint="" 当输入框没有内容时显示提示信息
其它属性与TextView类同
两个事件监听:
1、输入变化的事件监听:
addTextChangedListener(new TextWatcher(){
beforeTextChanged 文本改变之前
onTextChanged 文本正在改变
afterTextChanged 文本改变之后
});
2、编辑完成的动作监听(回车符)
setOnEditorActionListener(new OnEditorActionListener(){
onEditorAction() 实现编辑完成后的动作(比如提交内容)
});
四、Button组件:按钮
通常使用Button组件的单击事件来提交数据,或触发某个操作
1、实现Button的事件监听的三种方式:
<1>通过实现监听器接口:View.OnClickListener,通常在Activity界面来实现(也可以是其他界面类)
实现事件的处理方法:onClick(View v),通过判断参数组件的ID,来确定用户操作的是哪个按钮
switch(v.getId()) 实现不同按钮的操作
为每个按钮添加事件处理(setOnClickListener(this))
在处理多个按钮事件时,建议使用(效果最高)
<2>使用匿名内部类直接给按钮设置事件监听
setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
//......
}
});
使用此方式的好处,代码集中简洁,少量时使用,由于使用匿名内部类会生成单独的类,所以会影响一定
的性能。
<3>在布局文件中使用属性自定义单击事件的方法
在布局文件中用 android:onClick="方法名"
在Activity类中自定义方法:public void 方法名(View v){},好处简洁,但是有一定限制
以上三种方法:最好是第一种
2、配置按钮的样式:
<1>配置透明的按钮样式
在配置布局文件中的按钮组件上使用style属性:
style="?android:attr/borderlessButtonStyle"
或者设置
background="@null"
<2>配置自定义按钮的样式:
使用selector(选择器)
在res/drawbale目录下创建一个配置文件,比如 button_bg.xml
在文件中:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- state_pressed表示按下事件, drawable 可以是颜色或背景图片-->
<item android:state_pressed="true" android:drawable="@color/button_pressed"/>
<!-- 配置默认的样式 -->
<item android:drawable="@color/button_default"/>
</selector>
然后在按钮的布局设置中使用background属性引用资源配置文件:
background="@drawable/button_bg"
五、ImageButton组件
与Button按钮类似,表示一个图片按钮
1、通过src属性指定按钮上显示的图片
src="@mipmap/ic_launcher"
也可以通过定义一个selector来设置图片选择器,比如在drawable/imagebutton_bg.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@mipmap/de_btn_main_add_hover"/>
<item android:drawable="@mipmap/de_btn_main_add"/>
</selector>
2、定义按钮的形状(可以应用在所有按钮上)
定义 drawable/button_shape.xml
<!--
rectangle 矩形
corners 角度
padding 内边距
stroke 边界的线
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/colorAccent" />
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
<stroke android:color="#000000" android:width="5dp"/>
</shape>
六、ImageView组件
表示显示一个图片的组件
通过src属性指定要显示的图片资源
显示图片时要注意,以适当的大小进行显示,如果一个界面中出现大量较大的图片(占内存),那么
会出现内存溢出的情况,所以以合适的大小显示合适的图片由为重要
以适合的方式显示图片:就要对图片进行缩放
<1>定义组件的大小,让图片适应组件的方式来进行按宽高比自动缩放显示
maxHeight 图片显示的最大高度
maxWidth 图片显示的最大宽度
adjustViewBounds 保正图片的宽高比例
该方法将按原图的比例进行缩放
<2>使用scaleType对图片进行缩放
matrix 用矩阵来绘制,动态缩小放大图片来显示
fitXY 把图片不按比例扩大/缩小到View的大小显示
fitStart 把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置
fitCenter 把图片按比例扩大/缩小到View的宽度,居中显示
fitEnd 把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置
center 按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示
centerCrop 按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)
centerInside 将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或
小于View的长/宽
android:tint 将图片渲染成指定的颜色。
常用为:center、centerCrop
其它属性:
android:clickable="true" 是否可以单击,当该属性为true时,可以设置监听事件
注意:不要在小组件中显示大图片(图片组件的宽高小于图片本身的宽高)
七、CheckBox组件:复选框
用于提供多项选择
android:checked="true" 设置复选框是否默认选中
获取CheckBox组件的内容通常有两种方式:
<1>单获通过一个按钮的单击事件来检查CheckBox是否被选中
checkBox.isChecked() 判断是否为选中
再通过checkBox.getText().toString() 获取复选框的文本内容
checkBox.setChecked(boolean) 来设置是否选中
<2>通过给CheckBox组件添加CompoundButton.OnCheckedChangeListener事件
来监听复选框选中或取消选中的事件。
八、RadioButton和RadioGroup:单选按钮与分组
要想实现多个单选按钮互斥,需要把多个单选按钮放到一个RadioGroup分组内
可以为其中一个RadioButton设置为默认选中:checked="true"
RadioGroup中通过orientation属性设置水平或垂直排列
要想监听单选按钮的事件,可以通过实现RadioGroup.OnCheckedChangeListener接口
再通过radioGroup.findViewById(checkedId)获取当前被选中的RadioButton对象
再通过radioButton.getText()获取选中单选按钮的文本内容
或者通过一个按钮的单击事件来获取RadioButton的文本内容
使用RadioButton实现底部导航栏:
原理:利用RadioButton的互斥功能来实现底部导航菜单栏的功能
1、在界面底部使用RadioGroup组合多个RadioButton,并水平排列
2、设置RadioButton的相关属性来调整样式:
android:button="@null" 去除RadioButton的小圆圈
android:layout_weight="1" 平分多个RadioButton的位置
android:drawableTop="@drawable/..." 指定上方的图标
android:gravity="center" 居中显示
android:textColor="" 定义字体颜色
其中:drawableTop,textColor可以设置selector来改变选中与未选中的效果
九、ToggleButton、Switch:开关按钮
我们可以使用打关按钮来实现打开或关闭某一个功能的用户操作
textOn="打开" 按钮开启状态显示的文本
textOff="关闭" 按钮关闭状态显示的文本
在代码是通过isChecked方法来判断按钮的状态
监听开关按钮的事件:
setOnCheckedChangeListener()设置开关变化的事件
或者我们通过会使用单独的按钮进行统一的事件控制
十、RatingBar:评分条
可用于对用户、商品、用户体验等进行评分
<1>作为一个指示器,只提供查看
通过 android:isIndicator="true" 设置为指示器
<2>作为一个可与用户交互的评分
android:isIndicator="false" 默认值 用户可以点击
常用的属性:
android:numStars="5" 设置星的总数
android:stepSize="1" 设置步长(每次可以设置的递增值,可以是小数)
android:rating="3" 设置当前星数
事件监听:
当用户改变评分条的星数时,可以使用监听器接口:OnRatingBarChangeListener实现
ratingBar.setRating(4f);
ratingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
@Override
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
//ratingBar 评分条组件
//rating 当前改变后的评分值
//fromUser 是否是用户操作
if(fromUser){//是否是用户操作
///
System.out.println("当前已经设置的星数,rating="+rating);
}
}
});
注意:使用评分条时宽度要使用wrap_content,否则星数量将不可控制,误导用户
使用自定义评分条:(项目中使用)
1、在drawable下定义一个配置文件:
layer-list 图层列表
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@android:id/background"
android:drawable="@mipmap/star_small_bg" />
<item
android:id="@android:id/progress"
android:drawable="@mipmap/star_small_hl" />
</layer-list>
2、在style.xml文件中定义一个样式:
<style name="mySmallRatingBar" parent="android:Widget.RatingBar">
<item name="android:progressDrawable">@drawable/ratingbar_small_bg</item>
<item name="android:maxHeight">16dp</item>
<item name="android:minHeight">16dp</item>
</style>
3、在布局文件中定义RatingBar组件
用style属性引用自定义的样式
style="@style/mySmallRatingBar"
十一、Spinner组件:下拉列表
通过提供一组选项数据,让用户选择
实现一个Spinner组件:
1、在布局文件中定义Spinner组件
<Spinner
android:width="wrap_content"
android:height="wrap_content"
android:id="@+id/spinner_city">
2、给Spinner下拉列表提供数据
<1>通过字符串数组资源文件定义
res/values/strings.xml文件中定义:
<string-array name="city">
<item>北京市</item>
<item>上海市</item>
<item>深圳市</item>
<item>武汉市</item>
<string-array>
res/values/arrays.xml文件中定义:与strings.xml文件定义相同
<2>通过在代码中提供
通过是从其它地方获取数据(比如网络、数据库等)
3、利用一个适配器把数据填充到Spinner组件中
从资源文件中获取数据并创建一个适配器
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource();
createFromResource()参数:
<1>context : 上下文
<2>数据资源ID
<3>列表中用于显示数据的布局
通过直接创建ArrayAdapter的方式:
//获取资源对象
String[] citys = getResources().getStringArray(R.array.city);
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
this,R.layout.spinner_item,citys);
自定义下拉列表布局:
//使用自定义的布局文件
ArrayAdapter<CharSequence> adapter =ArrayAdapter.createFromResource(this,
R.array.city,R.layout.spinner_item);
spinner_item布局文件通常使用android默认的ID:@android:id/text1
//获取下拉列表当前选中的值
String city = spinner_city.getSelectedItem().toString();
十二、AutoCompleteTextView 自动完成
给用户提供建议选项
常用属性:
android:completionThreshold="1" 输入字符数,显示提示选项
android:completionHint="请选择一个城市" 提示信息
android:dropDownSelector="#def9de" 选中下拉列表的颜色
提供的建议列表,通过适配器提供
ArrayAdapter<CharSequence> arrayAdapter = ArrayAdapter.createFromResource(
this,R.array.city,android.R.layout.simple_list_item_1);
autoCompleteTextView.setAdapter(arrayAdapter);
十三、ProgressBar进度条组件
两种样式:
1、表盘样式(圆的,一直在转)
2、水平样式(提供进度值的可视,通常用于加载确定时间的操作提示)
默认是表盘样式,如需水平样式,通过设置 style属性
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
当进度条是可确定值的我们可以设置以下属性:
android:max="100" 进度条的最大值
android:progress="50" 当前的进度值
android:secondaryProgress="80" 当前的第二进度值
如果是水平样式,也可以通过indeterminate属性设置为进度不确定
android:indeterminate="true" true表示进度条不确定,false表示确定
如果为true进度条的样式将为重复水平滚动
ProgressDialog 对话框进度条
以对话框的方式显示进度条样式:
可以是表盘样式或水平样式
ProgressDialog pd = new ProgressDialog(this);
默认是表盘样式
设置为水平样式:
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置为水平样式
pd.setMax(100);//设置最大进度值
pd.setMessage("正在努力加载中...");
pd.setTitle("加载数据");
pd.setCancelable(true);//不允许取消
//监听对话框关闭的事件
pd.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
dialog.cancel();
}
});
pd.show(); //显示
模拟下载操作
private void showDialog(){
final ProgressDialog pd = new ProgressDialog(this);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setTitle("下载");
pd.setMessage("正在玩命下载中.....");
pd.setMax(100);
pd.setProgress(0);
pd.setCancelable(false);
pd.show();
//使用线程模拟一个下载操作
new Thread(new Runnable() {
@Override
public void run() {
while (true){
//判断进度值是否为最大值,如果是表示下载完成,取消对话框,结束线程
if(pd.getProgress()>=pd.getMax()){
pd.cancel();
break;
}
pd.incrementProgressBy(10);//增长进度
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
标题进度条(在标题栏的右上角使用表盘模式的进度条),一般不使用
自定义进度条:
1、在res/drawbale/layer_progress.xml
//fromDegrees 起始角度
//toDegrees 结束角度
//pivotX 旋转的中心点X坐标
//pivotY 旋转的中心点Y坐标
<layer-list>
<item>
<rotate android:drawable="@drawable/tab_discover_h" android:fromDegrees="0"
android:toDegrees="360" android:pivotX="50%" android:pivotY="50%"/>
</item>
</layer-list>
2、在布局文件中的ProgressBar组件定义时使用:
android:indeterminateDrawable="@drawable/layer_progress"
十四、AlertDialog对话框
对话框用窗口的方式与用户实现交互
1、创建 一个提示对话框:
//对话框的建造者
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("温馨提示:");
builder.setMessage("你真的要退出吗");
builder.setIcon(android.R.drawable.ic_menu_info_details);
builder.setCancelable(false);//不能被取消(指的是不能通过点击对话框以外的地方关闭)
//设置按钮
builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "程序已退出", Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "再玩会儿吧", Toast.LENGTH_SHORT).show();
}
});
builder.setNeutralButton("隐藏", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "啥也不说了", Toast.LENGTH_SHORT).show();
}
});
// builder.create().show();
builder.show();
}
2、列表选择对话框
注意:设置message后将不显示选项列表
测试数据:String[] names = {"宏才","大雷","张伟","闫鹏"};
<1>列表多选
列表选项中带复选框
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("多选列表");
//设置多项选择(选项数组,默认是否选中数组(null表示不选中),事件处理)
builder.setMultiChoiceItems(names, null, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
Toast.makeText(MainActivity.this, names[which], Toast.LENGTH_SHORT).show();
}
});
builder.show();
<2>列表单选
列表选项中带单选按钮
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("单选列表");
//设置单项选择(选项数组,默认是否选中(-1表示没有),事件处理)
builder.setSingleChoiceItems(names, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, names[which], Toast.LENGTH_SHORT).show();
}
});
builder.show();
<3>列表选项
只提供列表项选择一个
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("单选列表");
//设置选项(选项数组,事件处理)
builder.setItems(names, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, names[which], Toast.LENGTH_SHORT).show();
}
});
builder.show();
3、自定义对话框:
自定义对话框在未来开发中使用较多,意思是在对话框内的视图使用自定义布局的方式
1、自定义一个布局文件,在该文件中定义视图要显示的界面
2、在代码中加载布局文件:
ViewGroup:表示是否把布局填充到指定的父布局中,如果没有则使用null
<1>通过LayoutInflater.from(this).inflate(布局文件ID,ViewGroup);
<2>在Activity中可以使用
getLayoutInflater().inflate(布局文件ID,ViewGroup);
加载布局文件后返回一个View对象,该对象包含了布局文件中的所有组件
3、把返回的View对象通过builder.setView(view)方法设置到对话框中
4、如果需要获取View中的组件,可以通过:
view.findViewById(id)方法来获取
5、在6.0(API23)后builder提供了setView(布局文件的ID)方法来直接设置视图
十五、日期时间组件
1、时间对话框
<1>创建一个FragmentDialog的子类,用于创建一个可以兼容Fragment的对话框
如:TimePickerFragment extends FragmentDialog
<2>重写FragmentDialog的onCreateDialog()方法用于创建对话框
<3>onCreateDialog该方法返回一个TimePickerDialog对象:
TimePickerDialog dialog = new TimePickerDialog(getActivity(),this,hour,minute,true);
参数:
context: 上下文
OnTimeSetListener: 时间对话框确认按钮的回调事件:TimePickerDialog.OnTimeSetListener
hour : 小时
minute: 分钟
是否为24小时制:true
<4>实现OnTimeSetListener的onTimeSet方法
通过该方法来获取对话框中设置的时间值(可以显示在界面上或进行相应的处理)
<5>在Activity类中调用TimePickerFragment的show()方法,显示对话框
show()方法中的两个参数:Fragment管理器,字符串标记
2、日期对话框
<1>创建一个FragmentDialog的子类,用于创建一个可以兼容Fragment的对话框
如:DatePickerFragment extends FragmentDialog
<2>重写FragmentDialog的onCreateDialog()方法用于创建对话框
<3>onCreateDialog该方法返回一个DatePickerDialog对象:
DatePickerDialog dialog = new DatePickerDialog(getActivity(),this,year,month,day);
参数:
context: 上下文
OnDateSetListener: 时间对话框确认按钮的回调事件:DatePickerDialog.OnDateSetListener
year : 年
month: 月
day:日
<4>实现OnDateSetListener的onDateSet方法
通过该方法来获取对话框中设置的日期值(可以显示在界面上或进行相应的处理)
<5>在Activity类中调用DatePickerFragment的show()方法,显示对话框
show()方法中的两个参数:Fragment管理器,字符串标记
注意:
我们在Activity类中定义的UI组件,现在要通过另一个类(Fragment/*)来设值
实现方案是:
在Activity中定义一个公有方法来设置UI组件的值,该方法是提供给另一类来调用
十六、GridView组件
网络视图组件,在应用中通常可以用来作为功能列表界面
1、在布局文件中定义一个GridView组件:
<GridView
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:gravity="center" />
columnWidth:列宽
numColumns:总列数,使用auto_fit表示自动适配
stretchMode:伸展模式,columnWidth 以列宽的方式伸展
verticalSpacing:垂直间隔
horizontalSpacing:水平间隔
gravity:内容显示方式,center居中
2、在代码中获取组件:
GridView gridView = (GridView)findViewById(R.id.gridview);
3、自定义一个适配器类(继承BaseAdapter)
//内部类
/**
* 自定义适配器
*/
private static class MyAdapter extends BaseAdapter{
private String[] data;
private Context context;
public MyAdapter(Context context,String[] data){
this.context = context;
this.data = data;
}
//返回选项的总数
@Override
public int getCount() {
return data.length;
}
//获取每个选项的数据
@Override
public Object getItem(int position) {
return data[position];
}
//返回每个选项的ID
@Override
public long getItemId(int position) {
return position;
}
/**
* UI组件通过调用该方法获取一个视图,并填充到内部的选项中
* @param position
* @param convertView
* @param parent
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
System.out.println("getView------position="+position);
TextView tv = new TextView(context);
tv.setGravity(Gravity.CENTER);
tv.setText(data[position]);
return tv;
}
}
4、提供需要填充到适配器的数据:
String[] data = {"转帐","查水费","查电费","手机充值","公交充值","查天气","公积金",
"美食","世界那么大","外卖","快递","理财","彩票","股票","火车票"};
5、实例化适配器对象,并与组件绑定
MyAdapter adapter = new MyAdapter(this,data);
gridView.setAdapter(adapter);
6、设置选项的单击事件
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
System.out.println("parent="+parent);
System.out.println("view="+view);
System.out.println("position="+position);
System.out.println("id="+id);
TextView tv = (TextView) view;
Toast.makeText(MainActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
});
(二)使用自定义布局来设置每一个网格选项的内容:
1、创建一个布局文件,此文件的目的是给网格中的每一个选项定义视图
2、在自定义适配器中的getView方法加载布局(实例化)
View view = LayoutInflater.from(context).inflate(R.layout.item_layout,null);
3、再从view中查找相应的组件
ImageView iv = (ImageView)view.findViewById(R.id.imageView);
再为每一个子组件设置相应值:
iv.setImageResource(...)
return view;
十七、ListView组件
ListView以垂直列表的方式展示数据,在实际开发经常使用
1、使用资源文件数据绑定
<1>在values/arrays.xml(strings.xml) 定义一组字符串数据
<string-array name="names">
<item>宏才</item>
<item>大雷</item>
<item>大张伟</item>
<item>大龙神</item>
<item>学霸朝旭</item>
</string-array>
<2>在ListView的布局文件声明中使用
android:entries="@array/names" 绑定资源文件
<3>在Activity中获取ListView组件,并设置选项单击事件
ListView listView = (ListView) findViewById(R.id.listView);
//设置选项单击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//parent : ListView组件
//view:每一个列表选项视图
//position:列表选项的位置
//id:ID
TextView tv = (TextView) view;
Toast.makeText(MainActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
});
基本属性配置:
android:dividerHeight="30dp" 间隔高度
android:divider="@color/colorAccent" 间隔颜色
android:listSelector="#b9f9f9" 列表项被选中的颜色
android:fastScrollEnabled="true" 快速滚动时滚动条启用小方块
android:scrollbars="vertical" 滑动时显示滚动条
2、使用ListActivity实现列表(了解)
<1>Activity类继承ListActivity
在ListActivity中默认自带一个ListView组件,继承ListActivity后不需要自定义主布局文件
<2>可以通过ListActivity中定义的getListView()方法获取ListView
<3>使用ListActivity类中定义的setListAdapter()方法设置适配器(绑定数据)
<4>重写ListActivity类中定义的onListItemClick方法实现列表单击事件
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
TextView tv = (TextView) v;
Toast.makeText(Main2Activity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
3、单选与多选ListView
<1>单选:
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this,R.array.names,android.R.layout.simple_list_item_single_choice);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
<2>多选:
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this,R.array.names,android.R.layout.simple_list_item_multiple_choice);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
4、使用SimpleAdapter填充复杂布局(ListView)
<1>封装要填充的数据格式:
//一个Map对象表示列表中的一个选项,再把多个Map对象组装成List集合
Map<String,Object> row1 = new HashMap<>();
row1.put("image",android.R.drawable.ic_delete);
row1.put("text","删除信息");
//
List<Map<String,Object>> data = new ArrayList<>();
data.add(row1);
//data.add(row2);
//data.add(row3);
<2>自定义一个选项布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:gravity="center_vertical"
android:padding="16dp"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
android:layout_marginRight="16dp"
android:id="@+id/imageView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView" />
</LinearLayout>
<3>创建SimpleAdapter给ListView填充数据
String[] from = {"image","text"}; //要填充的数据对应的key
int[] to = {R.id.imageView,R.id.textView}; //要把数据填充到对应的组件
//参数:
//Context:上下文
//data:要填充的数据(格式为 List<? extends Map<String,?>> )
//resource int类型,每个选项的布局(ID)
//from:数组,map中的key值
//to:数组,选项布局中的组件ID
SimpleAdapter adapter = new SimpleAdapter(
this,initData(),R.layout.item_layout,from,to);
listView.setAdapter(adapter);
5、使用自定义适配器填充复杂的布局(ListView)
<1>定义一个选项布局
<2>自定义一个适配器继承BaseAdapter
private static class MyAdapter extends BaseAdapter{
private Context context;
private String[] titles = {
"百度音乐","拨号","电子邮件","短信","计算器","联系人","日历","设置","时钟","图库","微信",
"下载"};
private int[] images = {
R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,
R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,
R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,
R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher
};
public MyAdapter(Context context){
this.context = context;
}
@Override
public int getCount() {
return titles.length;
}
@Override
public Object getItem(int position) {
return titles[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(R.layout.item_layout,null);
ImageView iv = (ImageView) view.findViewById(R.id.imageView);
TextView tv = (TextView) view.findViewById(R.id.textView);
iv.setImageResource(images[position]);
tv.setText(titles[position]);
return view;
}
}
<3>创建自定义适配器对象,并设置到ListView中
listView.setAdapter(new MyAdapter(this));
<4>设置选项单击事件:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView tv = (TextView) view.findViewById(R.id.textView);
Toast.makeText(Main5Activity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
});
6、ListView的优化:
原因是ListView列表项通常比较多,用户在来回滚动时需要考虑性能问题,否则会出现内存溢出或卡顿情况
解决问题:
<1>减少列表视图对象的创建,可以重复利用
<2>提高组件赋值时查找组件的效率
优化分为3点:
1、让ListView组件的大小相对固定,可以避免ListView组件在加载选项时重复渲染
比如:不要使用wrap_content 来设置ListView的宽高
2、利用适配器中的getView方法的convertView参数,来解决列表选项视图对象每次重新创建的问题
通过这样做:
if(convertView==null) convertView = LayoutInflater.inflate(R.layout.item,null);
3、在列表选项视图比较复杂的情况下, 每次都通过findViewById去查找组件会影响性能
解决方法是:
定义一个ViewHolder类作为选项视图中组件的缓存,在创建选项视图对象(View)时查找视图中的
组件后存储到一个ViewHolder对象中,再把ViewHolder保存到View上(view.setTag(ViewHolder))
在下次重复给组件赋值时通过view.getTag()获取ViewHolder对象,再给ViewHolder内存储的组件赋值
一个ViewHolder类通常是这样的:(可以作为适配器的内部类)
private static class ViewHolder{
ImageView iv;
TextView tv;
//......
}
注意:
面试题:问如何优化ListView组件?
7、使用ListView实现分页功能(每加载一页数据都进行累加)
<1>、首先初始化第一页显示的数据
<2>、在ListView组件的底部添加一个提示加载数据的视图
<3>、实现滚动条的监听事件(OnScrollListener)
<4>、监听滚动条滑动到ListView的底部,并且滚动条的状态是空闲状态
<5>、使用线程模拟加载数据(一切耗时的操作必须在子线程中完成)
<6>、线程加载完数据后,需要通知主线程(UI线程)更新UI组件
<7>、主线程与子线程之间通讯使用Handler(消息处理器)
<8>、在消息处理器中判断消息标记,更新UI,adapter.notifyDataSetChanged()
十八、ExpandableListView
可扩展的ListView,提供两层列表视图,可用于分组列表
1、在主布局中使用:
<ExpandableListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/ex_listView"/>
2、添加一个分组布局
3、添加一个每个组内的布局
4、ExpandableListView填充数据需要继承适配器BaseExpandableListAdapter
十九、ImageSwitcher和TextSwitcher
ImageSwitcher实现两个图片的切换
TextWatcher实现两个文本内容的切换
ImageSwitcher和TextSwitcher的实现方式相似
ImageSwitcher组件的使用:
1、在主布局文件中定义组件:
2、在Activity类中实现ViewSwitcher.ViewFactory视图工厂接口
用于为ImageSwitcher提供显示图片的视图组件(ImageView)
public View makeView() {
ImageView iv = new ImageView(this);
iv.setImageResource(images[0]);
return iv;
}
然后调用imageSwitcher.setFactory(this)方法设置视图工厂
3、在实现手势滑动ImageSwitcher组件时实现图片的切换需要实现View.OnTouchListener
触屏事件接口,并实现 public boolean onTouch(View v, MotionEvent event) 方法
比如:
private int index = 0;//表示当前显示的图片下标
private float startX,endX; //用于记录屏幕按下的X坐标,和放开的X坐标
/**
* 屏幕触摸事件
* @param v 发生触摸事件的组件
* @param event 触摸事件
* @return
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if(MotionEvent.ACTION_DOWN==action){
//按下屏幕
startX = event.getX();
return true;
}else if(MotionEvent.ACTION_UP==action){
endX = event.getX();
if(startX-endX>=50){
//表示向左滑动
index = index+1<images.length?++index:0;
imageSwitcher.setInAnimation(this,R.anim.slide_in_right);
imageSwitcher.setOutAnimation(this,android.R.anim.fade_out);
imageSwitcher.setImageResource(images[index]);
}else if(endX-startX>=50){
//表示向右滑动
index = index-1>=0?--index:images.length-1;
imageSwitcher.setInAnimation(this,android.R.anim.slide_in_left);
imageSwitcher.setOutAnimation(this,android.R.anim.fade_out);
imageSwitcher.setImageResource(images[index]);
}
}
return true;
}
4、在ImageSwitcher上注册触屏事件:
imageSwitcher.setOnTouchListener(this);
TextSwitcher组件的使用与ImageSwitcher类似,代码如下:
布局文件:
<TextSwitcher
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textSwitcher"></TextSwitcher>
Activity类代码:
public class Main2Activity extends AppCompatActivity
implements ViewSwitcher.ViewFactory,View.OnTouchListener{
private TextSwitcher textSwitcher;
private String[] text = {"床前明月光","我叫郭德纲"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
textSwitcher = (TextSwitcher) findViewById(R.id.textSwitcher);
textSwitcher.setFactory(this);
textSwitcher.setOnTouchListener(this);
}
private int index = 0;//表示当前显示的图片下标
private float startX,endX; //用于记录屏幕按下的X坐标,和放开的X坐标
/**
* 屏幕触摸事件
* @param v 发生触摸事件的组件
* @param event 触摸事件
* @return
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if(MotionEvent.ACTION_DOWN==action){
//按下屏幕
startX = event.getX();
return true;
}else if(MotionEvent.ACTION_UP==action){
endX = event.getX();
if(startX-endX>=50){
//表示向左滑动
index = index+1<text.length?++index:0;
textSwitcher.setInAnimation(this,android.R.anim.fade_in);
textSwitcher.setOutAnimation(this,android.R.anim.fade_out);
textSwitcher.setText(text[index]);
}else if(endX-startX>=50){
//表示向右滑动
index = index-1>=0?--index:text.length-1;
textSwitcher.setInAnimation(this,android.R.anim.fade_in);
textSwitcher.setOutAnimation(this,android.R.anim.fade_out);
textSwitcher.setText(text[index]);
}
}
return true;
}
@Override
public View makeView() {
TextView tv = new TextView(this);
tv.setTextSize(30);
tv.setGravity(Gravity.CENTER);
tv.setTextColor(Color.RED);
tv.setText(text[0]);
return tv;
}
}
二十、ViewFlipper组件
实现多个视图组件的切换,比ImageSwitcher和TextSwitcher只针对图片和文本内容来说,显示的视图
更加丰富。
实现一个ViewFlipper切换是这样的:
1、布局文件:
<ViewFlipper
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/viewFlipper"
android:background="#4b4a4a"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="centerInside"
android:src="@mipmap/zw1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:padding="16dp"
android:gravity="center"
android:text="美女1"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="centerInside"
android:src="@mipmap/zw2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:padding="16dp"
android:gravity="center"
android:text="美女2"/>
</LinearLayout>
</ViewFlipper>
2、定义切换动画:
在anim/下创建动画配置文件:
<1>anim/in_leftright.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%p" android:toXDelta="0"
android:duration="500"/>
</set>
<2>anim/in_rightleft.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0"
android:duration="500"/>
</set>
<3>anim/out_leftright.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="100%p"
android:duration="500"/>
</set>
<4>anim/out_rightleft.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-100%p"
android:duration="500"/>
</set>
3、Activity类:
public class Main3Activity extends AppCompatActivity implements View.OnTouchListener{
private ViewFlipper viewFlipper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
viewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);
viewFlipper.setOnTouchListener(this);
}
float startX,endX;
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
startX = event.getX();
break;
case MotionEvent.ACTION_UP:
endX = event.getX();
if(startX-endX>=50){
//向左
viewFlipper.setInAnimation(this,R.anim.in_rightleft);
viewFlipper.setOutAnimation(this,R.anim.out_rightleft);
viewFlipper.showNext();
}else if(endX-startX>=50){
//向右
viewFlipper.setInAnimation(this,R.anim.in_leftright);
viewFlipper.setOutAnimation(this,R.anim.out_leftright);
viewFlipper.showPrevious();
}
break;
}
return true;
}
}
二十一、Menu菜单
1、选项菜单(OptionMenu)
在Activity界面的标题栏处显示(ActionBar)
通常使用选项菜单有两种方式:
<1>通过代码添加选项菜单
(1)重写onCreateOptionsMenu(Menu menu)方法,实现菜单的创建
(2)重写onOptionsItemSelected(MenuItem item)方法,实现菜单的单击事件
<2>通过XML配置菜单(推荐)
(1)在res/menu/下创建菜单配置文件
(2)重写onCreateOptionsMenu(Menu menu)方法,通过getMenuInflater().inflate()方法填充菜单
(3)重写onOptionsItemSelected(Menu menu)方法,实现菜单的单击事件
配置菜单XML文件:res/menu/option_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/set_menu" //菜单项的ID
android:icon="@android:drawable/ic_menu_set_as" //菜单项的图标
android:orderInCategory="100" //菜单项的排序位置,从小到大
android:title="设置" //菜单的标题
//该属性是api11(3.0)后可以使用,需要添加命名空间
//xmlns:app="http://schemas.android.com/apk/res-auto"
//表示如何设置显示动作:
//ifRoom 有空间时显示
//withText 显示文本标题
//always 一直显示
//never 总是不显示
//collapseActionView 使用自定义视图
app:showAsAction="ifRoom|withText" />
//配置子菜单
<item android:title="颜色">
<menu>
<item android:title="红色" android:id="@+id/red"/>
<item android:title="蓝色" android:id="@+id/blue"/>
</meun>
</item>
</menu>
2、上下文菜单(ContextMenu)
上下文菜单是依赖于界面上的某一个组件,在使用时,长按该组件会弹出菜单,这样菜单就是上下文
菜单。
实现上下文菜单:
<1>在res/menu/下创建一个菜单配置文件,比如:context_menu.xml
<2>在Activity中重写onCreateContextMenu()方法,用于创建上下文菜单
<3>在Activity中重写onContextItemSelected方法,实现菜单的选项单击事件
<4>调用registerForContextMenu(View)方法把上下文菜单注册到某一个组件上
那么长按该组件,会弹出上下文菜单
3、弹出式菜单(PopupMenu)
//创建弹出式菜单(context,要把菜单显示在哪个组件的旁边)
PopupMenu popupMenu = new PopupMenu(this,view);
//加载菜单配置文件
popupMenu.getMenuInflater().inflate(R.menu.popup_menu,popupMenu.getMenu());
//设置菜单选项的单击事件
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
case R.id.color_red:
Toast.makeText(Main4Activity.this, "red", Toast.LENGTH_SHORT).show();
break;
case R.id.color_green:
Toast.makeText(Main4Activity.this, "green", Toast.LENGTH_SHORT).show();
break;
case R.id.color_yellow:
Toast.makeText(Main4Activity.this, "yellow", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
});
//显示弹出式菜单
popupMenu.show();
4
面试题 :问菜单一共有多少种,分别是什么
1、OptionsMenu
2、ContextMenu
3、PopupMenu
菜单上可以添加子菜单
二十二、ViewPager组件
用于多个页面的横向切换
一、示例
在一个界面(Activity、Fragment)实现ViewPager切换多个页面
1、在主布局文件中声明ViewPager组件
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTabStrip
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v4.view.ViewPager>
2、为每一个切换的视图定义单独的布局文件:
<1>定义layout1.xml
<2>定义layout2.xml
<3>定义layout3.xml
<4>定义layout4.xml
3、实例化4个布局文件,可以使用List集合存储视图对象,目的是在切换页面时方便获取
ArrayList<View> views = new ArrayList<View>();
View v1 = getLayoutInflater().inflate(R.layout.layout1,null);
View v2 = getLayoutInflater().inflate(R.layout.layout2,null);
View v3 = getLayoutInflater().inflate(R.layout.layout3,null);
View v4 = getLayoutInflater().inflate(R.layout.layout4,null);
4、定义适配器,继承PagerAdapter,通常要实现以下方法:
<1>getCount()
获取切换页面的总数
<2> isViewFromObject(View view, Object object)
判断视图是否为指定对象,便于重复使用视图
<3>instantiateItem(ViewGroup container, int position)
显示页面时用于实例化页面视图,通过我们在该方法中返回一个页面视图对象
(该视图对象从已实例化好的集合中获取)
<4>destroyItem(ViewGroup container, int position, Object object)
页面切换时销毁上一个页面视图,通常我们需要把上一个视图从container容器中删除
<5>getPageTitle(int position)
当ViewPager组件使用了标题组件时,可以通过该方法返回一个标题文本显示
5、实例化适配器对象,并设置到ViewPager组件上
6、设置相关属性
viewPager = (ViewPager) findViewById(R.id.viewPager);
tab = (PagerTabStrip) findViewById(R.id.tab);
//设置背景颜色
tab.setBackgroundResource(R.color.colorPrimaryDark);
//指示器的颜色
tab.setTabIndicatorColor(Color.WHITE);
//指示器文本颜色
tab.setTextColor(Color.WHITE);
//指示器底部线(false去除)
tab.setDrawFullUnderline(false);
//当前选择的选项卡
viewPager.setCurrentItem(1);
//每个选项卡之前的间隔
viewPager.setPageMargin(1);
7、监听页面切换事件
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
//页面滚动
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
//页面被选中(通常在该方法实现页面数据加载)
public void onPageSelected(int position)
//页面滚动状态变化
public void onPageScrollStateChanged(int state)
}
二、实现一个程序启动的引导页功能
1、在布局文件中添加ViewPager组件和用于表示当前页选中的小圆点图片(数量与页卡相同)
并调整好位置。
2、自定义PageAdapter配适器填充布局,同上
3、获取布局中的小圆点图片并存储到ArrayList中,便于切换小圆点图片状态用
private ArrayList<ImageView> imageViews = new ArrayList<>();
private void initView(){
View v1 = getLayoutInflater().inflate(R.layout.indicator_layout1,null);
View v2 = getLayoutInflater().inflate(R.layout.indicator_layout2,null);
View v3 = getLayoutInflater().inflate(R.layout.indicator_layout3,null);
View v4 = getLayoutInflater().inflate(R.layout.indicator_layout4,null);
views.add(v1);
views.add(v2);
views.add(v3);
views.add(v4);
}
4、实现ViewPager的OnPageChangeListener事件的onPageSelected()方法
@Override
public void onPageSelected(int position) {
setSelectedPoint(position);
}
private int prevIndex = 0;
private void setSelectedPoint(int position) {
if(prevIndex!=position) {
//设置上一个被选中的,对应位置的小圆点为未选中状态图片
imageViews.get(prevIndex).setImageResource(R.mipmap.default_holo);
}
//设置当前被选中的,对应位置的小圆点为选中状态图片
imageViews.get(position).setImageResource(R.mipmap.touched_holo);
prevIndex = position;
}
二十三、PopupWindow组件
用于实现弹窗功能
1、使用PopupWindow组件是直接在代码中实例化对象
private PopupWindow createPopupWindow(){
View view = getLayoutInflater().inflate(R.layout.window_layout,null);
//创建PopupWindow(布局视图组件,宽度,高度)
final PopupWindow popupWindow = new PopupWindow(view,
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
//设置弹窗内的按钮事件
view.findViewById(R.id.button_delete).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "delete", Toast.LENGTH_SHORT).show();
popupWindow.dismiss();
}
});
view.findViewById(R.id.button2_update).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "update", Toast.LENGTH_SHORT).show();
popupWindow.dismiss();
}
});
//动画效果
popupWindow.setAnimationStyle(android.R.anim.fade_in);
//设置背景
popupWindow.setBackgroundDrawable(getResources().getDrawable(R.mipmap.de_btn_login_sign_in));
//透明度
popupWindow.getBackground().setAlpha(50);
//获取焦点
popupWindow.setFocusable(true);
//可以触摸
popupWindow.setTouchable(true);
//防止虚拟软键盘被弹出菜单遮住
popupWindow.setInputMethodMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
popupWindow.setOutsideTouchable(true);
// popupWindow.showAtLocation(view, Gravity.BOTTOM,0,0);
return popupWindow;
}
2、在一个按钮上单击后弹出弹窗:
PopupWindow popupWindow = createPopupWindow();
public void showPopupWindow(View view){
popupWindow.showAtLocation(view,Gravity.BOTTOM,0,0);
}
// 获取屏幕和PopupWindow的width和height
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
mScreenHeight = dm.heightPixels;
mScreenWidth = dm.widthPixels;
二十四、Notifactions(通知)
android系统提供了一个通知栏,任何程序可以在通知栏中显示本程序的通知,相互之间不会冲突
1、发送一个普通通知:
//创建一个通知的构建者来设置通知的相关数据(包括v4,v7)
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
//必须设置的参数3个
builder.setSmallIcon(R.mipmap.ic_launcher); //设置小图标
builder.setContentTitle("你有一条新消息"); //设置内容的标题
builder.setContentText("新消息:贱贱说:"); //设置内容
//可选参数:
builder.setTicker("你有一条新消息");//设置通知时在顶部自动提示的信息
//通过一个资源文件创建 一个Bitmap对象(BitmapFactory用于创建Bitmap的工厂类)
Bitmap b = BitmapFactory.decodeResource(getResources(),android.R.drawable.ic_menu_call)
//设置一个大图标
builder.setLargeIcon(b);
//设置通知的声音,震动,呼吸灯为默认系统设置,注意震动需添加权限
builder.setDefaults(Notification.DEFAULT_ALL);
//添加权限在清单文件中:
<uses-permission android:name="android.permission.VIBRATE"/>
builder.setAutoCancel(true); //自动取消通知(需要添加单击事件)
builder.setOngoing(true); //常驻通知,只能在程序在清除
//创建一个通知对象
Notification n = builder.build();
//发送通知需要使用一个系统级的 通知管理器服务 此对象由系统来管理
NotificationManager nm = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID,n);
2、给通知添加单击事件
//-------------给通知添加单击事件---------------
//创建一个意图,(Context,要打开的界面Activity)
Intent intent = new Intent(this,ContentActivity.class);
intent.putExtra("info","新消息:贱贱说:下午请大家吃冰棍儿");
//PendingIntent 延迟的Intent
//PendingIntent.FLAG_UPDATE_CURRENT:
//表示如果PendingIntent已经存在,那么更新内容后使用,没有就创建一个
PendingIntent pi = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pi); //设置内容的意图(Intent)
//在另一个通知事件打开的Activity中获取数据
String info = getIntent().getStringExtra("info");
textView_content.setText(info);
3、添加大视图通知
//添加大视图的样式
NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
style.setBigContentTitle("波波吟诗:");
style.setSummaryText("作者:bobo");
style.addLine("长亭外");
style.addLine("古道边");
style.addLine("一行白鹭上青天");
builder.setStyle(style);
注意,大视图样式在4.1版本后支持,高度为256dp
4、显示进度条下载样式的通知
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("下载");
builder.setContentText("正在下载中...");
builder.setProgress(100,0,false);//设置进度条(最大值,当前进度,是不是不确定的进度)
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_3,builder.build());
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=100;i++){
builder.setProgress(100,i,false);
nm.notify(NID_3,builder.build());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
builder.setContentText("下载完成");
nm.notify(NID_3,builder.build());
nm.cancel(NID_3);
}
}).start();
5、自定义通知视图:
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);//必须设置小图标
//创建一个远程视图对象,目的把该视图添加到系统的通知栏(通知栏属于系统的程序)
RemoteViews views = new RemoteViews(getPackageName(),R.layout.custom_layout);
//为远程视图组件设置图片
views.setImageViewBitmap(R.id.imageView,
BitmapFactory.decodeResource(getResources(),android.R.drawable.ic_dialog_email));
// views.setImageViewResource(R.id.imageView,R.mipmap.ic_launcher);
views.setImageViewResource(R.id.imageButton2_play_pause,
android.R.drawable.ic_media_pause);
// views.setOnClickPendingIntent();//为某一个组件设置单击事件
builder.setContent(views);
PendingIntent pi = PendingIntent.getActivity(
this,0,new Intent(this,ContentActivity.class),0);
builder.setContentIntent(pi);
NotificationManager nm = (NotificationManager) getSystemService(
Context.NOTIFICATION_SERVICE);
nm.notify(NID_4,builder.build());
6、其它(了解一下)
//设置声音
// builder.setDefaults(Notification.DEFAULT_SOUND);
// builder.setSound();
//设置震动
// builder.setDefaults(Notification.DEFAULT_VIBRATE);
// builder.setVibrate(new long[]{0,1000,200,1000});
//设置呼吸灯
// builder.setDefaults(Notification.DEFAULT_LIGHTS);
// builder.setLights(Color.BLUE,1000,1000);
7、小结:在开发应用中通常使用到通知的情况:
<1>普通通知(*****)
<2>自定义通知视频(播放器类的应用中)
用于实现自动提醒功能(例如:新闻消息,短信,消息推送等)
二十五:样式与主题
1、样式
样式是在程序中通一设置一种风格,可以应用在组件上称为样式,应用在Activity上或app上称为主题
在res/values/style.xml文件中定义样式:
例如:
<style name="AppTheme.My">
<item name="colorPrimary">#f77e7e</item>
<item name="colorPrimaryDark">#f43939</item>
<item name="colorAccent">#d1d1d1</item>
</style>
<!--通过parent继承系统的样式-->
<style name="MyTextStyle" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:textColor">#454545</item>
<item name="android:textSize">16sp</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
<!--通过上一个样式的 父样式名称.名称 来继承自已的定义的样式 -->
<style name="MyTextStyle.secondTitle">
<item name="android:textColor">#9f9f9f</item>
<item name="android:textSize">12sp</item>
</style>
二十六:自定义组件
自定义组件的三种方式:
<1>、组合现有组件(比如继承一个ViewGroup或布局类)
<2>、继承一个现有的组件进行扩展
<3>、继承View根类完全自定义
1、继承一个组件示例:
<1>自定义属性文件:res/values/attrs.xml文件中定义:
<declare-styleable name="MyCheckBox">
<attr name="value" format="string|reference"></attr>
<attr name="myColor" format="color|reference"></attr>
</declare-styleable>
<2>自定义组件类
public class MyCheckBox extends CheckBox {
private String value;
private int myColor;
//getter and setter...
public MyCheckBox(Context context) {
super(context);
}
public MyCheckBox(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyCheckBox);
//获取属性值
value = array.getString(R.styleable.MyCheckBox_value);
myColor = array.getColor(R.styleable.MyCheckBox_myColor,Color.BLACK);
this.setTextColor(myColor);
//释放
array.recycle();
}
}
<3>在布局文件中使用自定义组件:
引入命名空间
xmlns:app="http://schemas.android.com/apk/res-auto"
<com.moliying.ui_customview.MyCheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/myCheckBox"
android:text="同意协议"
app:value="yes"
app:myColor="@color/colorAccent"
/>
2、通过继承View实现自定义组件
<1>创建一个类继承View,重写构造方法
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
}
//定义自己的属性
private int color;
private String text;
private int textSize;
//getter and setter...
<2>在attrs.xml文件中定义属性:
<declare-styleable name="MyView">
<attr name="textColor" format="color|reference"/>
<attr name="text" format="string|reference"/>
<attr name="textSize" format="integer|reference"/>
</declare-styleable>
<3>在构造方法中获取属性值:
public MyView(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyView);
//获取属性值
textColor = array.getColor(R.styleable.MyView_textColor, Color.BLACK);
text = array.getString(R.styleable.MyView_text);
textSize = array.getInt(R.styleable.MyView_textSize,20);
array.recycle();//释放
}
<4>重写onDraw方法实现绘制
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
p.setColor(textColor);
p.setTextSize(textSize);
p.setStyle(Paint.Style.FILL);// 设置画笔的样式 FILL:实心 STROKE:空心
canvas.drawText(text,10,textSize,p); //绘制文本内容
}
<5>在布局文件中使用自定义组件:
<com.moliying.ui_customview.MyView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:text="非磨砺 不能赢"
app:textColor="@color/colorAccent"
app:textSize="50"
android:layout_below="@+id/button_submit"
android:layout_alignParentStart="true"
android:layout_marginTop="58dp" />
3、解决在ListView/GridView与ScrollView嵌套时的滚动冲突
问题描述:
ListView嵌套ScrollView时,由于ListView的滚动事件会被ScrollView的滚动事件响应,导致
ListView滚动事件无效,会出现ListView内容显示不全的情况,解决方法是重新计算ListView的高度
让所有Item显示出来。
<1>自定义一个类继承ListView,重写计算宽高的方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//重新计算ListView的最大的高度
//makeMeasureSpec(最大值,模式(AT_MOST表示最大数))
heightMeasureSpec = MeasureSpec
.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
<2>在布局文件中使用自定义的ListView即可
一、Toast:显示提示信息
1、显示文件内容:
Toast.makeText(context,"文本内容",时间).show();
时间:Toast.LENGTH_LONG 时间长一点
Toast.LENGTH_SHORT 时间短一点
Context:表示上下文对象,可以表示整个应用程序的上下文对象(应用程序级全局对象),也可以表示
一个界面的上下文对象(Activity)
2、显示图片
Toast t = new Toast(this); //创建Toast对象
ImageView view = new ImageView(this); //创建一个图片组件
view.setImageResource(R.mipmap.ic_launcher); //为图片组件设置图片资源
t.setView(view); //把图片组件设置到Toast组件上
t.setDuration(Toast.LENGTH_LONG);//设置显示的时间
t.show();//显示
3、显示图文
<1>创建 一个布局对象,用于组合多个组件,比如(LinearLayout)
<2>设置布局组件的相关属性(比如方向,内部组件显示的相对位置)
<3>创建需要添加到布局组件中的组件对象(ImageView 和 TextView)
<4>分别为组件对象设置内容(图片组件设置图片资源,文本组件设置文本内容)
<5>通过addView(...)方法把组件添加到布局组件中
<6>再把布局组件添加到Toast上,显示
通过这个示例,我们了解如何通过代码的方式组合组件,再显示到界面上
二、TextView组件
常用的属性设置:
android:textIsSelectable="true" 设置文本内容可选(触发系统的复制粘贴功能)
android:drawableLeft="@mipmap/ic_launcher" 设置文本内容的图标
其它包括drawableRight, drawableTop, drawableBottom, drawableStart, drawableEnd
android:text="Hello World!" 设置显示的文本内容
android:textColor="@color/colorAccent" 设置文本颜色
android:textSize="24sp" 设置文本字体大小
android:textStyle="bold" 设置字体的样式(bold 粗体,normal 默认, italic 斜体)
android:clickable="true" 是否可以单击
android:onClick="" 可单击的情况下,可以设置单击事件
android:ellipsize="marquee" 设置文本内容超出显示范围的显示方式
end, marquee, middle, none, start
android:lines="1" 设置显示的行数
android:maxLines="1" 最大的行数
android:minLines="1" 最小的行数
android:gravity 设置文本内容的位置
android:background="@color/colorPrimary" 设置背景颜色
三、EditText输入组件,是TextView的子类
用于接收输入文本内容
常用的属性:
android:hint="" 当输入框没有内容时显示提示信息
其它属性与TextView类同
两个事件监听:
1、输入变化的事件监听:
addTextChangedListener(new TextWatcher(){
beforeTextChanged 文本改变之前
onTextChanged 文本正在改变
afterTextChanged 文本改变之后
});
2、编辑完成的动作监听(回车符)
setOnEditorActionListener(new OnEditorActionListener(){
onEditorAction() 实现编辑完成后的动作(比如提交内容)
});
四、Button组件:按钮
通常使用Button组件的单击事件来提交数据,或触发某个操作
1、实现Button的事件监听的三种方式:
<1>通过实现监听器接口:View.OnClickListener,通常在Activity界面来实现(也可以是其他界面类)
实现事件的处理方法:onClick(View v),通过判断参数组件的ID,来确定用户操作的是哪个按钮
switch(v.getId()) 实现不同按钮的操作
为每个按钮添加事件处理(setOnClickListener(this))
在处理多个按钮事件时,建议使用(效果最高)
<2>使用匿名内部类直接给按钮设置事件监听
setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
//......
}
});
使用此方式的好处,代码集中简洁,少量时使用,由于使用匿名内部类会生成单独的类,所以会影响一定
的性能。
<3>在布局文件中使用属性自定义单击事件的方法
在布局文件中用 android:onClick="方法名"
在Activity类中自定义方法:public void 方法名(View v){},好处简洁,但是有一定限制
以上三种方法:最好是第一种
2、配置按钮的样式:
<1>配置透明的按钮样式
在配置布局文件中的按钮组件上使用style属性:
style="?android:attr/borderlessButtonStyle"
或者设置
background="@null"
<2>配置自定义按钮的样式:
使用selector(选择器)
在res/drawbale目录下创建一个配置文件,比如 button_bg.xml
在文件中:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- state_pressed表示按下事件, drawable 可以是颜色或背景图片-->
<item android:state_pressed="true" android:drawable="@color/button_pressed"/>
<!-- 配置默认的样式 -->
<item android:drawable="@color/button_default"/>
</selector>
然后在按钮的布局设置中使用background属性引用资源配置文件:
background="@drawable/button_bg"
五、ImageButton组件
与Button按钮类似,表示一个图片按钮
1、通过src属性指定按钮上显示的图片
src="@mipmap/ic_launcher"
也可以通过定义一个selector来设置图片选择器,比如在drawable/imagebutton_bg.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@mipmap/de_btn_main_add_hover"/>
<item android:drawable="@mipmap/de_btn_main_add"/>
</selector>
2、定义按钮的形状(可以应用在所有按钮上)
定义 drawable/button_shape.xml
<!--
rectangle 矩形
corners 角度
padding 内边距
stroke 边界的线
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/colorAccent" />
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
<stroke android:color="#000000" android:width="5dp"/>
</shape>
六、ImageView组件
表示显示一个图片的组件
通过src属性指定要显示的图片资源
显示图片时要注意,以适当的大小进行显示,如果一个界面中出现大量较大的图片(占内存),那么
会出现内存溢出的情况,所以以合适的大小显示合适的图片由为重要
以适合的方式显示图片:就要对图片进行缩放
<1>定义组件的大小,让图片适应组件的方式来进行按宽高比自动缩放显示
maxHeight 图片显示的最大高度
maxWidth 图片显示的最大宽度
adjustViewBounds 保正图片的宽高比例
该方法将按原图的比例进行缩放
<2>使用scaleType对图片进行缩放
matrix 用矩阵来绘制,动态缩小放大图片来显示
fitXY 把图片不按比例扩大/缩小到View的大小显示
fitStart 把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置
fitCenter 把图片按比例扩大/缩小到View的宽度,居中显示
fitEnd 把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置
center 按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示
centerCrop 按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)
centerInside 将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或
小于View的长/宽
android:tint 将图片渲染成指定的颜色。
常用为:center、centerCrop
其它属性:
android:clickable="true" 是否可以单击,当该属性为true时,可以设置监听事件
注意:不要在小组件中显示大图片(图片组件的宽高小于图片本身的宽高)
七、CheckBox组件:复选框
用于提供多项选择
android:checked="true" 设置复选框是否默认选中
获取CheckBox组件的内容通常有两种方式:
<1>单获通过一个按钮的单击事件来检查CheckBox是否被选中
checkBox.isChecked() 判断是否为选中
再通过checkBox.getText().toString() 获取复选框的文本内容
checkBox.setChecked(boolean) 来设置是否选中
<2>通过给CheckBox组件添加CompoundButton.OnCheckedChangeListener事件
来监听复选框选中或取消选中的事件。
八、RadioButton和RadioGroup:单选按钮与分组
要想实现多个单选按钮互斥,需要把多个单选按钮放到一个RadioGroup分组内
可以为其中一个RadioButton设置为默认选中:checked="true"
RadioGroup中通过orientation属性设置水平或垂直排列
要想监听单选按钮的事件,可以通过实现RadioGroup.OnCheckedChangeListener接口
再通过radioGroup.findViewById(checkedId)获取当前被选中的RadioButton对象
再通过radioButton.getText()获取选中单选按钮的文本内容
或者通过一个按钮的单击事件来获取RadioButton的文本内容
使用RadioButton实现底部导航栏:
原理:利用RadioButton的互斥功能来实现底部导航菜单栏的功能
1、在界面底部使用RadioGroup组合多个RadioButton,并水平排列
2、设置RadioButton的相关属性来调整样式:
android:button="@null" 去除RadioButton的小圆圈
android:layout_weight="1" 平分多个RadioButton的位置
android:drawableTop="@drawable/..." 指定上方的图标
android:gravity="center" 居中显示
android:textColor="" 定义字体颜色
其中:drawableTop,textColor可以设置selector来改变选中与未选中的效果
九、ToggleButton、Switch:开关按钮
我们可以使用打关按钮来实现打开或关闭某一个功能的用户操作
textOn="打开" 按钮开启状态显示的文本
textOff="关闭" 按钮关闭状态显示的文本
在代码是通过isChecked方法来判断按钮的状态
监听开关按钮的事件:
setOnCheckedChangeListener()设置开关变化的事件
或者我们通过会使用单独的按钮进行统一的事件控制
十、RatingBar:评分条
可用于对用户、商品、用户体验等进行评分
<1>作为一个指示器,只提供查看
通过 android:isIndicator="true" 设置为指示器
<2>作为一个可与用户交互的评分
android:isIndicator="false" 默认值 用户可以点击
常用的属性:
android:numStars="5" 设置星的总数
android:stepSize="1" 设置步长(每次可以设置的递增值,可以是小数)
android:rating="3" 设置当前星数
事件监听:
当用户改变评分条的星数时,可以使用监听器接口:OnRatingBarChangeListener实现
ratingBar.setRating(4f);
ratingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
@Override
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
//ratingBar 评分条组件
//rating 当前改变后的评分值
//fromUser 是否是用户操作
if(fromUser){//是否是用户操作
///
System.out.println("当前已经设置的星数,rating="+rating);
}
}
});
注意:使用评分条时宽度要使用wrap_content,否则星数量将不可控制,误导用户
使用自定义评分条:(项目中使用)
1、在drawable下定义一个配置文件:
layer-list 图层列表
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@android:id/background"
android:drawable="@mipmap/star_small_bg" />
<item
android:id="@android:id/progress"
android:drawable="@mipmap/star_small_hl" />
</layer-list>
2、在style.xml文件中定义一个样式:
<style name="mySmallRatingBar" parent="android:Widget.RatingBar">
<item name="android:progressDrawable">@drawable/ratingbar_small_bg</item>
<item name="android:maxHeight">16dp</item>
<item name="android:minHeight">16dp</item>
</style>
3、在布局文件中定义RatingBar组件
用style属性引用自定义的样式
style="@style/mySmallRatingBar"
十一、Spinner组件:下拉列表
通过提供一组选项数据,让用户选择
实现一个Spinner组件:
1、在布局文件中定义Spinner组件
<Spinner
android:width="wrap_content"
android:height="wrap_content"
android:id="@+id/spinner_city">
2、给Spinner下拉列表提供数据
<1>通过字符串数组资源文件定义
res/values/strings.xml文件中定义:
<string-array name="city">
<item>北京市</item>
<item>上海市</item>
<item>深圳市</item>
<item>武汉市</item>
<string-array>
res/values/arrays.xml文件中定义:与strings.xml文件定义相同
<2>通过在代码中提供
通过是从其它地方获取数据(比如网络、数据库等)
3、利用一个适配器把数据填充到Spinner组件中
从资源文件中获取数据并创建一个适配器
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource();
createFromResource()参数:
<1>context : 上下文
<2>数据资源ID
<3>列表中用于显示数据的布局
通过直接创建ArrayAdapter的方式:
//获取资源对象
String[] citys = getResources().getStringArray(R.array.city);
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(
this,R.layout.spinner_item,citys);
自定义下拉列表布局:
//使用自定义的布局文件
ArrayAdapter<CharSequence> adapter =ArrayAdapter.createFromResource(this,
R.array.city,R.layout.spinner_item);
spinner_item布局文件通常使用android默认的ID:@android:id/text1
//获取下拉列表当前选中的值
String city = spinner_city.getSelectedItem().toString();
十二、AutoCompleteTextView 自动完成
给用户提供建议选项
常用属性:
android:completionThreshold="1" 输入字符数,显示提示选项
android:completionHint="请选择一个城市" 提示信息
android:dropDownSelector="#def9de" 选中下拉列表的颜色
提供的建议列表,通过适配器提供
ArrayAdapter<CharSequence> arrayAdapter = ArrayAdapter.createFromResource(
this,R.array.city,android.R.layout.simple_list_item_1);
autoCompleteTextView.setAdapter(arrayAdapter);
十三、ProgressBar进度条组件
两种样式:
1、表盘样式(圆的,一直在转)
2、水平样式(提供进度值的可视,通常用于加载确定时间的操作提示)
默认是表盘样式,如需水平样式,通过设置 style属性
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
当进度条是可确定值的我们可以设置以下属性:
android:max="100" 进度条的最大值
android:progress="50" 当前的进度值
android:secondaryProgress="80" 当前的第二进度值
如果是水平样式,也可以通过indeterminate属性设置为进度不确定
android:indeterminate="true" true表示进度条不确定,false表示确定
如果为true进度条的样式将为重复水平滚动
ProgressDialog 对话框进度条
以对话框的方式显示进度条样式:
可以是表盘样式或水平样式
ProgressDialog pd = new ProgressDialog(this);
默认是表盘样式
设置为水平样式:
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置为水平样式
pd.setMax(100);//设置最大进度值
pd.setMessage("正在努力加载中...");
pd.setTitle("加载数据");
pd.setCancelable(true);//不允许取消
//监听对话框关闭的事件
pd.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
dialog.cancel();
}
});
pd.show(); //显示
模拟下载操作
private void showDialog(){
final ProgressDialog pd = new ProgressDialog(this);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setTitle("下载");
pd.setMessage("正在玩命下载中.....");
pd.setMax(100);
pd.setProgress(0);
pd.setCancelable(false);
pd.show();
//使用线程模拟一个下载操作
new Thread(new Runnable() {
@Override
public void run() {
while (true){
//判断进度值是否为最大值,如果是表示下载完成,取消对话框,结束线程
if(pd.getProgress()>=pd.getMax()){
pd.cancel();
break;
}
pd.incrementProgressBy(10);//增长进度
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
标题进度条(在标题栏的右上角使用表盘模式的进度条),一般不使用
自定义进度条:
1、在res/drawbale/layer_progress.xml
//fromDegrees 起始角度
//toDegrees 结束角度
//pivotX 旋转的中心点X坐标
//pivotY 旋转的中心点Y坐标
<layer-list>
<item>
<rotate android:drawable="@drawable/tab_discover_h" android:fromDegrees="0"
android:toDegrees="360" android:pivotX="50%" android:pivotY="50%"/>
</item>
</layer-list>
2、在布局文件中的ProgressBar组件定义时使用:
android:indeterminateDrawable="@drawable/layer_progress"
十四、AlertDialog对话框
对话框用窗口的方式与用户实现交互
1、创建 一个提示对话框:
//对话框的建造者
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("温馨提示:");
builder.setMessage("你真的要退出吗");
builder.setIcon(android.R.drawable.ic_menu_info_details);
builder.setCancelable(false);//不能被取消(指的是不能通过点击对话框以外的地方关闭)
//设置按钮
builder.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "程序已退出", Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "再玩会儿吧", Toast.LENGTH_SHORT).show();
}
});
builder.setNeutralButton("隐藏", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "啥也不说了", Toast.LENGTH_SHORT).show();
}
});
// builder.create().show();
builder.show();
}
2、列表选择对话框
注意:设置message后将不显示选项列表
测试数据:String[] names = {"宏才","大雷","张伟","闫鹏"};
<1>列表多选
列表选项中带复选框
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("多选列表");
//设置多项选择(选项数组,默认是否选中数组(null表示不选中),事件处理)
builder.setMultiChoiceItems(names, null, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
Toast.makeText(MainActivity.this, names[which], Toast.LENGTH_SHORT).show();
}
});
builder.show();
<2>列表单选
列表选项中带单选按钮
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("单选列表");
//设置单项选择(选项数组,默认是否选中(-1表示没有),事件处理)
builder.setSingleChoiceItems(names, -1, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, names[which], Toast.LENGTH_SHORT).show();
}
});
builder.show();
<3>列表选项
只提供列表项选择一个
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("单选列表");
//设置选项(选项数组,事件处理)
builder.setItems(names, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, names[which], Toast.LENGTH_SHORT).show();
}
});
builder.show();
3、自定义对话框:
自定义对话框在未来开发中使用较多,意思是在对话框内的视图使用自定义布局的方式
1、自定义一个布局文件,在该文件中定义视图要显示的界面
2、在代码中加载布局文件:
ViewGroup:表示是否把布局填充到指定的父布局中,如果没有则使用null
<1>通过LayoutInflater.from(this).inflate(布局文件ID,ViewGroup);
<2>在Activity中可以使用
getLayoutInflater().inflate(布局文件ID,ViewGroup);
加载布局文件后返回一个View对象,该对象包含了布局文件中的所有组件
3、把返回的View对象通过builder.setView(view)方法设置到对话框中
4、如果需要获取View中的组件,可以通过:
view.findViewById(id)方法来获取
5、在6.0(API23)后builder提供了setView(布局文件的ID)方法来直接设置视图
十五、日期时间组件
1、时间对话框
<1>创建一个FragmentDialog的子类,用于创建一个可以兼容Fragment的对话框
如:TimePickerFragment extends FragmentDialog
<2>重写FragmentDialog的onCreateDialog()方法用于创建对话框
<3>onCreateDialog该方法返回一个TimePickerDialog对象:
TimePickerDialog dialog = new TimePickerDialog(getActivity(),this,hour,minute,true);
参数:
context: 上下文
OnTimeSetListener: 时间对话框确认按钮的回调事件:TimePickerDialog.OnTimeSetListener
hour : 小时
minute: 分钟
是否为24小时制:true
<4>实现OnTimeSetListener的onTimeSet方法
通过该方法来获取对话框中设置的时间值(可以显示在界面上或进行相应的处理)
<5>在Activity类中调用TimePickerFragment的show()方法,显示对话框
show()方法中的两个参数:Fragment管理器,字符串标记
2、日期对话框
<1>创建一个FragmentDialog的子类,用于创建一个可以兼容Fragment的对话框
如:DatePickerFragment extends FragmentDialog
<2>重写FragmentDialog的onCreateDialog()方法用于创建对话框
<3>onCreateDialog该方法返回一个DatePickerDialog对象:
DatePickerDialog dialog = new DatePickerDialog(getActivity(),this,year,month,day);
参数:
context: 上下文
OnDateSetListener: 时间对话框确认按钮的回调事件:DatePickerDialog.OnDateSetListener
year : 年
month: 月
day:日
<4>实现OnDateSetListener的onDateSet方法
通过该方法来获取对话框中设置的日期值(可以显示在界面上或进行相应的处理)
<5>在Activity类中调用DatePickerFragment的show()方法,显示对话框
show()方法中的两个参数:Fragment管理器,字符串标记
注意:
我们在Activity类中定义的UI组件,现在要通过另一个类(Fragment/*)来设值
实现方案是:
在Activity中定义一个公有方法来设置UI组件的值,该方法是提供给另一类来调用
十六、GridView组件
网络视图组件,在应用中通常可以用来作为功能列表界面
1、在布局文件中定义一个GridView组件:
<GridView
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:gravity="center" />
columnWidth:列宽
numColumns:总列数,使用auto_fit表示自动适配
stretchMode:伸展模式,columnWidth 以列宽的方式伸展
verticalSpacing:垂直间隔
horizontalSpacing:水平间隔
gravity:内容显示方式,center居中
2、在代码中获取组件:
GridView gridView = (GridView)findViewById(R.id.gridview);
3、自定义一个适配器类(继承BaseAdapter)
//内部类
/**
* 自定义适配器
*/
private static class MyAdapter extends BaseAdapter{
private String[] data;
private Context context;
public MyAdapter(Context context,String[] data){
this.context = context;
this.data = data;
}
//返回选项的总数
@Override
public int getCount() {
return data.length;
}
//获取每个选项的数据
@Override
public Object getItem(int position) {
return data[position];
}
//返回每个选项的ID
@Override
public long getItemId(int position) {
return position;
}
/**
* UI组件通过调用该方法获取一个视图,并填充到内部的选项中
* @param position
* @param convertView
* @param parent
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
System.out.println("getView------position="+position);
TextView tv = new TextView(context);
tv.setGravity(Gravity.CENTER);
tv.setText(data[position]);
return tv;
}
}
4、提供需要填充到适配器的数据:
String[] data = {"转帐","查水费","查电费","手机充值","公交充值","查天气","公积金",
"美食","世界那么大","外卖","快递","理财","彩票","股票","火车票"};
5、实例化适配器对象,并与组件绑定
MyAdapter adapter = new MyAdapter(this,data);
gridView.setAdapter(adapter);
6、设置选项的单击事件
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
System.out.println("parent="+parent);
System.out.println("view="+view);
System.out.println("position="+position);
System.out.println("id="+id);
TextView tv = (TextView) view;
Toast.makeText(MainActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
});
(二)使用自定义布局来设置每一个网格选项的内容:
1、创建一个布局文件,此文件的目的是给网格中的每一个选项定义视图
2、在自定义适配器中的getView方法加载布局(实例化)
View view = LayoutInflater.from(context).inflate(R.layout.item_layout,null);
3、再从view中查找相应的组件
ImageView iv = (ImageView)view.findViewById(R.id.imageView);
再为每一个子组件设置相应值:
iv.setImageResource(...)
return view;
十七、ListView组件
ListView以垂直列表的方式展示数据,在实际开发经常使用
1、使用资源文件数据绑定
<1>在values/arrays.xml(strings.xml) 定义一组字符串数据
<string-array name="names">
<item>宏才</item>
<item>大雷</item>
<item>大张伟</item>
<item>大龙神</item>
<item>学霸朝旭</item>
</string-array>
<2>在ListView的布局文件声明中使用
android:entries="@array/names" 绑定资源文件
<3>在Activity中获取ListView组件,并设置选项单击事件
ListView listView = (ListView) findViewById(R.id.listView);
//设置选项单击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//parent : ListView组件
//view:每一个列表选项视图
//position:列表选项的位置
//id:ID
TextView tv = (TextView) view;
Toast.makeText(MainActivity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
});
基本属性配置:
android:dividerHeight="30dp" 间隔高度
android:divider="@color/colorAccent" 间隔颜色
android:listSelector="#b9f9f9" 列表项被选中的颜色
android:fastScrollEnabled="true" 快速滚动时滚动条启用小方块
android:scrollbars="vertical" 滑动时显示滚动条
2、使用ListActivity实现列表(了解)
<1>Activity类继承ListActivity
在ListActivity中默认自带一个ListView组件,继承ListActivity后不需要自定义主布局文件
<2>可以通过ListActivity中定义的getListView()方法获取ListView
<3>使用ListActivity类中定义的setListAdapter()方法设置适配器(绑定数据)
<4>重写ListActivity类中定义的onListItemClick方法实现列表单击事件
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
TextView tv = (TextView) v;
Toast.makeText(Main2Activity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
3、单选与多选ListView
<1>单选:
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this,R.array.names,android.R.layout.simple_list_item_single_choice);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
<2>多选:
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this,R.array.names,android.R.layout.simple_list_item_multiple_choice);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
4、使用SimpleAdapter填充复杂布局(ListView)
<1>封装要填充的数据格式:
//一个Map对象表示列表中的一个选项,再把多个Map对象组装成List集合
Map<String,Object> row1 = new HashMap<>();
row1.put("image",android.R.drawable.ic_delete);
row1.put("text","删除信息");
//
List<Map<String,Object>> data = new ArrayList<>();
data.add(row1);
//data.add(row2);
//data.add(row3);
<2>自定义一个选项布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:gravity="center_vertical"
android:padding="16dp"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
android:layout_marginRight="16dp"
android:id="@+id/imageView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView" />
</LinearLayout>
<3>创建SimpleAdapter给ListView填充数据
String[] from = {"image","text"}; //要填充的数据对应的key
int[] to = {R.id.imageView,R.id.textView}; //要把数据填充到对应的组件
//参数:
//Context:上下文
//data:要填充的数据(格式为 List<? extends Map<String,?>> )
//resource int类型,每个选项的布局(ID)
//from:数组,map中的key值
//to:数组,选项布局中的组件ID
SimpleAdapter adapter = new SimpleAdapter(
this,initData(),R.layout.item_layout,from,to);
listView.setAdapter(adapter);
5、使用自定义适配器填充复杂的布局(ListView)
<1>定义一个选项布局
<2>自定义一个适配器继承BaseAdapter
private static class MyAdapter extends BaseAdapter{
private Context context;
private String[] titles = {
"百度音乐","拨号","电子邮件","短信","计算器","联系人","日历","设置","时钟","图库","微信",
"下载"};
private int[] images = {
R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,
R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,
R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher,
R.mipmap.ic_launcher,R.mipmap.ic_launcher,R.mipmap.ic_launcher
};
public MyAdapter(Context context){
this.context = context;
}
@Override
public int getCount() {
return titles.length;
}
@Override
public Object getItem(int position) {
return titles[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(R.layout.item_layout,null);
ImageView iv = (ImageView) view.findViewById(R.id.imageView);
TextView tv = (TextView) view.findViewById(R.id.textView);
iv.setImageResource(images[position]);
tv.setText(titles[position]);
return view;
}
}
<3>创建自定义适配器对象,并设置到ListView中
listView.setAdapter(new MyAdapter(this));
<4>设置选项单击事件:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView tv = (TextView) view.findViewById(R.id.textView);
Toast.makeText(Main5Activity.this, tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
});
6、ListView的优化:
原因是ListView列表项通常比较多,用户在来回滚动时需要考虑性能问题,否则会出现内存溢出或卡顿情况
解决问题:
<1>减少列表视图对象的创建,可以重复利用
<2>提高组件赋值时查找组件的效率
优化分为3点:
1、让ListView组件的大小相对固定,可以避免ListView组件在加载选项时重复渲染
比如:不要使用wrap_content 来设置ListView的宽高
2、利用适配器中的getView方法的convertView参数,来解决列表选项视图对象每次重新创建的问题
通过这样做:
if(convertView==null) convertView = LayoutInflater.inflate(R.layout.item,null);
3、在列表选项视图比较复杂的情况下, 每次都通过findViewById去查找组件会影响性能
解决方法是:
定义一个ViewHolder类作为选项视图中组件的缓存,在创建选项视图对象(View)时查找视图中的
组件后存储到一个ViewHolder对象中,再把ViewHolder保存到View上(view.setTag(ViewHolder))
在下次重复给组件赋值时通过view.getTag()获取ViewHolder对象,再给ViewHolder内存储的组件赋值
一个ViewHolder类通常是这样的:(可以作为适配器的内部类)
private static class ViewHolder{
ImageView iv;
TextView tv;
//......
}
注意:
面试题:问如何优化ListView组件?
7、使用ListView实现分页功能(每加载一页数据都进行累加)
<1>、首先初始化第一页显示的数据
<2>、在ListView组件的底部添加一个提示加载数据的视图
<3>、实现滚动条的监听事件(OnScrollListener)
<4>、监听滚动条滑动到ListView的底部,并且滚动条的状态是空闲状态
<5>、使用线程模拟加载数据(一切耗时的操作必须在子线程中完成)
<6>、线程加载完数据后,需要通知主线程(UI线程)更新UI组件
<7>、主线程与子线程之间通讯使用Handler(消息处理器)
<8>、在消息处理器中判断消息标记,更新UI,adapter.notifyDataSetChanged()
十八、ExpandableListView
可扩展的ListView,提供两层列表视图,可用于分组列表
1、在主布局中使用:
<ExpandableListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/ex_listView"/>
2、添加一个分组布局
3、添加一个每个组内的布局
4、ExpandableListView填充数据需要继承适配器BaseExpandableListAdapter
十九、ImageSwitcher和TextSwitcher
ImageSwitcher实现两个图片的切换
TextWatcher实现两个文本内容的切换
ImageSwitcher和TextSwitcher的实现方式相似
ImageSwitcher组件的使用:
1、在主布局文件中定义组件:
2、在Activity类中实现ViewSwitcher.ViewFactory视图工厂接口
用于为ImageSwitcher提供显示图片的视图组件(ImageView)
public View makeView() {
ImageView iv = new ImageView(this);
iv.setImageResource(images[0]);
return iv;
}
然后调用imageSwitcher.setFactory(this)方法设置视图工厂
3、在实现手势滑动ImageSwitcher组件时实现图片的切换需要实现View.OnTouchListener
触屏事件接口,并实现 public boolean onTouch(View v, MotionEvent event) 方法
比如:
private int index = 0;//表示当前显示的图片下标
private float startX,endX; //用于记录屏幕按下的X坐标,和放开的X坐标
/**
* 屏幕触摸事件
* @param v 发生触摸事件的组件
* @param event 触摸事件
* @return
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if(MotionEvent.ACTION_DOWN==action){
//按下屏幕
startX = event.getX();
return true;
}else if(MotionEvent.ACTION_UP==action){
endX = event.getX();
if(startX-endX>=50){
//表示向左滑动
index = index+1<images.length?++index:0;
imageSwitcher.setInAnimation(this,R.anim.slide_in_right);
imageSwitcher.setOutAnimation(this,android.R.anim.fade_out);
imageSwitcher.setImageResource(images[index]);
}else if(endX-startX>=50){
//表示向右滑动
index = index-1>=0?--index:images.length-1;
imageSwitcher.setInAnimation(this,android.R.anim.slide_in_left);
imageSwitcher.setOutAnimation(this,android.R.anim.fade_out);
imageSwitcher.setImageResource(images[index]);
}
}
return true;
}
4、在ImageSwitcher上注册触屏事件:
imageSwitcher.setOnTouchListener(this);
TextSwitcher组件的使用与ImageSwitcher类似,代码如下:
布局文件:
<TextSwitcher
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/textSwitcher"></TextSwitcher>
Activity类代码:
public class Main2Activity extends AppCompatActivity
implements ViewSwitcher.ViewFactory,View.OnTouchListener{
private TextSwitcher textSwitcher;
private String[] text = {"床前明月光","我叫郭德纲"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
textSwitcher = (TextSwitcher) findViewById(R.id.textSwitcher);
textSwitcher.setFactory(this);
textSwitcher.setOnTouchListener(this);
}
private int index = 0;//表示当前显示的图片下标
private float startX,endX; //用于记录屏幕按下的X坐标,和放开的X坐标
/**
* 屏幕触摸事件
* @param v 发生触摸事件的组件
* @param event 触摸事件
* @return
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
if(MotionEvent.ACTION_DOWN==action){
//按下屏幕
startX = event.getX();
return true;
}else if(MotionEvent.ACTION_UP==action){
endX = event.getX();
if(startX-endX>=50){
//表示向左滑动
index = index+1<text.length?++index:0;
textSwitcher.setInAnimation(this,android.R.anim.fade_in);
textSwitcher.setOutAnimation(this,android.R.anim.fade_out);
textSwitcher.setText(text[index]);
}else if(endX-startX>=50){
//表示向右滑动
index = index-1>=0?--index:text.length-1;
textSwitcher.setInAnimation(this,android.R.anim.fade_in);
textSwitcher.setOutAnimation(this,android.R.anim.fade_out);
textSwitcher.setText(text[index]);
}
}
return true;
}
@Override
public View makeView() {
TextView tv = new TextView(this);
tv.setTextSize(30);
tv.setGravity(Gravity.CENTER);
tv.setTextColor(Color.RED);
tv.setText(text[0]);
return tv;
}
}
二十、ViewFlipper组件
实现多个视图组件的切换,比ImageSwitcher和TextSwitcher只针对图片和文本内容来说,显示的视图
更加丰富。
实现一个ViewFlipper切换是这样的:
1、布局文件:
<ViewFlipper
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/viewFlipper"
android:background="#4b4a4a"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="centerInside"
android:src="@mipmap/zw1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:padding="16dp"
android:gravity="center"
android:text="美女1"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="centerInside"
android:src="@mipmap/zw2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:padding="16dp"
android:gravity="center"
android:text="美女2"/>
</LinearLayout>
</ViewFlipper>
2、定义切换动画:
在anim/下创建动画配置文件:
<1>anim/in_leftright.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%p" android:toXDelta="0"
android:duration="500"/>
</set>
<2>anim/in_rightleft.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0"
android:duration="500"/>
</set>
<3>anim/out_leftright.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="100%p"
android:duration="500"/>
</set>
<4>anim/out_rightleft.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-100%p"
android:duration="500"/>
</set>
3、Activity类:
public class Main3Activity extends AppCompatActivity implements View.OnTouchListener{
private ViewFlipper viewFlipper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
viewFlipper = (ViewFlipper) findViewById(R.id.viewFlipper);
viewFlipper.setOnTouchListener(this);
}
float startX,endX;
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
startX = event.getX();
break;
case MotionEvent.ACTION_UP:
endX = event.getX();
if(startX-endX>=50){
//向左
viewFlipper.setInAnimation(this,R.anim.in_rightleft);
viewFlipper.setOutAnimation(this,R.anim.out_rightleft);
viewFlipper.showNext();
}else if(endX-startX>=50){
//向右
viewFlipper.setInAnimation(this,R.anim.in_leftright);
viewFlipper.setOutAnimation(this,R.anim.out_leftright);
viewFlipper.showPrevious();
}
break;
}
return true;
}
}
二十一、Menu菜单
1、选项菜单(OptionMenu)
在Activity界面的标题栏处显示(ActionBar)
通常使用选项菜单有两种方式:
<1>通过代码添加选项菜单
(1)重写onCreateOptionsMenu(Menu menu)方法,实现菜单的创建
(2)重写onOptionsItemSelected(MenuItem item)方法,实现菜单的单击事件
<2>通过XML配置菜单(推荐)
(1)在res/menu/下创建菜单配置文件
(2)重写onCreateOptionsMenu(Menu menu)方法,通过getMenuInflater().inflate()方法填充菜单
(3)重写onOptionsItemSelected(Menu menu)方法,实现菜单的单击事件
配置菜单XML文件:res/menu/option_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/set_menu" //菜单项的ID
android:icon="@android:drawable/ic_menu_set_as" //菜单项的图标
android:orderInCategory="100" //菜单项的排序位置,从小到大
android:title="设置" //菜单的标题
//该属性是api11(3.0)后可以使用,需要添加命名空间
//xmlns:app="http://schemas.android.com/apk/res-auto"
//表示如何设置显示动作:
//ifRoom 有空间时显示
//withText 显示文本标题
//always 一直显示
//never 总是不显示
//collapseActionView 使用自定义视图
app:showAsAction="ifRoom|withText" />
//配置子菜单
<item android:title="颜色">
<menu>
<item android:title="红色" android:id="@+id/red"/>
<item android:title="蓝色" android:id="@+id/blue"/>
</meun>
</item>
</menu>
2、上下文菜单(ContextMenu)
上下文菜单是依赖于界面上的某一个组件,在使用时,长按该组件会弹出菜单,这样菜单就是上下文
菜单。
实现上下文菜单:
<1>在res/menu/下创建一个菜单配置文件,比如:context_menu.xml
<2>在Activity中重写onCreateContextMenu()方法,用于创建上下文菜单
<3>在Activity中重写onContextItemSelected方法,实现菜单的选项单击事件
<4>调用registerForContextMenu(View)方法把上下文菜单注册到某一个组件上
那么长按该组件,会弹出上下文菜单
3、弹出式菜单(PopupMenu)
//创建弹出式菜单(context,要把菜单显示在哪个组件的旁边)
PopupMenu popupMenu = new PopupMenu(this,view);
//加载菜单配置文件
popupMenu.getMenuInflater().inflate(R.menu.popup_menu,popupMenu.getMenu());
//设置菜单选项的单击事件
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
case R.id.color_red:
Toast.makeText(Main4Activity.this, "red", Toast.LENGTH_SHORT).show();
break;
case R.id.color_green:
Toast.makeText(Main4Activity.this, "green", Toast.LENGTH_SHORT).show();
break;
case R.id.color_yellow:
Toast.makeText(Main4Activity.this, "yellow", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
});
//显示弹出式菜单
popupMenu.show();
4
面试题 :问菜单一共有多少种,分别是什么
1、OptionsMenu
2、ContextMenu
3、PopupMenu
菜单上可以添加子菜单
二十二、ViewPager组件
用于多个页面的横向切换
一、示例
在一个界面(Activity、Fragment)实现ViewPager切换多个页面
1、在主布局文件中声明ViewPager组件
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTabStrip
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v4.view.ViewPager>
2、为每一个切换的视图定义单独的布局文件:
<1>定义layout1.xml
<2>定义layout2.xml
<3>定义layout3.xml
<4>定义layout4.xml
3、实例化4个布局文件,可以使用List集合存储视图对象,目的是在切换页面时方便获取
ArrayList<View> views = new ArrayList<View>();
View v1 = getLayoutInflater().inflate(R.layout.layout1,null);
View v2 = getLayoutInflater().inflate(R.layout.layout2,null);
View v3 = getLayoutInflater().inflate(R.layout.layout3,null);
View v4 = getLayoutInflater().inflate(R.layout.layout4,null);
4、定义适配器,继承PagerAdapter,通常要实现以下方法:
<1>getCount()
获取切换页面的总数
<2> isViewFromObject(View view, Object object)
判断视图是否为指定对象,便于重复使用视图
<3>instantiateItem(ViewGroup container, int position)
显示页面时用于实例化页面视图,通过我们在该方法中返回一个页面视图对象
(该视图对象从已实例化好的集合中获取)
<4>destroyItem(ViewGroup container, int position, Object object)
页面切换时销毁上一个页面视图,通常我们需要把上一个视图从container容器中删除
<5>getPageTitle(int position)
当ViewPager组件使用了标题组件时,可以通过该方法返回一个标题文本显示
5、实例化适配器对象,并设置到ViewPager组件上
6、设置相关属性
viewPager = (ViewPager) findViewById(R.id.viewPager);
tab = (PagerTabStrip) findViewById(R.id.tab);
//设置背景颜色
tab.setBackgroundResource(R.color.colorPrimaryDark);
//指示器的颜色
tab.setTabIndicatorColor(Color.WHITE);
//指示器文本颜色
tab.setTextColor(Color.WHITE);
//指示器底部线(false去除)
tab.setDrawFullUnderline(false);
//当前选择的选项卡
viewPager.setCurrentItem(1);
//每个选项卡之前的间隔
viewPager.setPageMargin(1);
7、监听页面切换事件
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
//页面滚动
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
//页面被选中(通常在该方法实现页面数据加载)
public void onPageSelected(int position)
//页面滚动状态变化
public void onPageScrollStateChanged(int state)
}
二、实现一个程序启动的引导页功能
1、在布局文件中添加ViewPager组件和用于表示当前页选中的小圆点图片(数量与页卡相同)
并调整好位置。
2、自定义PageAdapter配适器填充布局,同上
3、获取布局中的小圆点图片并存储到ArrayList中,便于切换小圆点图片状态用
private ArrayList<ImageView> imageViews = new ArrayList<>();
private void initView(){
View v1 = getLayoutInflater().inflate(R.layout.indicator_layout1,null);
View v2 = getLayoutInflater().inflate(R.layout.indicator_layout2,null);
View v3 = getLayoutInflater().inflate(R.layout.indicator_layout3,null);
View v4 = getLayoutInflater().inflate(R.layout.indicator_layout4,null);
views.add(v1);
views.add(v2);
views.add(v3);
views.add(v4);
}
4、实现ViewPager的OnPageChangeListener事件的onPageSelected()方法
@Override
public void onPageSelected(int position) {
setSelectedPoint(position);
}
private int prevIndex = 0;
private void setSelectedPoint(int position) {
if(prevIndex!=position) {
//设置上一个被选中的,对应位置的小圆点为未选中状态图片
imageViews.get(prevIndex).setImageResource(R.mipmap.default_holo);
}
//设置当前被选中的,对应位置的小圆点为选中状态图片
imageViews.get(position).setImageResource(R.mipmap.touched_holo);
prevIndex = position;
}
二十三、PopupWindow组件
用于实现弹窗功能
1、使用PopupWindow组件是直接在代码中实例化对象
private PopupWindow createPopupWindow(){
View view = getLayoutInflater().inflate(R.layout.window_layout,null);
//创建PopupWindow(布局视图组件,宽度,高度)
final PopupWindow popupWindow = new PopupWindow(view,
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
//设置弹窗内的按钮事件
view.findViewById(R.id.button_delete).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "delete", Toast.LENGTH_SHORT).show();
popupWindow.dismiss();
}
});
view.findViewById(R.id.button2_update).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "update", Toast.LENGTH_SHORT).show();
popupWindow.dismiss();
}
});
//动画效果
popupWindow.setAnimationStyle(android.R.anim.fade_in);
//设置背景
popupWindow.setBackgroundDrawable(getResources().getDrawable(R.mipmap.de_btn_login_sign_in));
//透明度
popupWindow.getBackground().setAlpha(50);
//获取焦点
popupWindow.setFocusable(true);
//可以触摸
popupWindow.setTouchable(true);
//防止虚拟软键盘被弹出菜单遮住
popupWindow.setInputMethodMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
popupWindow.setOutsideTouchable(true);
// popupWindow.showAtLocation(view, Gravity.BOTTOM,0,0);
return popupWindow;
}
2、在一个按钮上单击后弹出弹窗:
PopupWindow popupWindow = createPopupWindow();
public void showPopupWindow(View view){
popupWindow.showAtLocation(view,Gravity.BOTTOM,0,0);
}
// 获取屏幕和PopupWindow的width和height
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
mScreenHeight = dm.heightPixels;
mScreenWidth = dm.widthPixels;
二十四、Notifactions(通知)
android系统提供了一个通知栏,任何程序可以在通知栏中显示本程序的通知,相互之间不会冲突
1、发送一个普通通知:
//创建一个通知的构建者来设置通知的相关数据(包括v4,v7)
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
//必须设置的参数3个
builder.setSmallIcon(R.mipmap.ic_launcher); //设置小图标
builder.setContentTitle("你有一条新消息"); //设置内容的标题
builder.setContentText("新消息:贱贱说:"); //设置内容
//可选参数:
builder.setTicker("你有一条新消息");//设置通知时在顶部自动提示的信息
//通过一个资源文件创建 一个Bitmap对象(BitmapFactory用于创建Bitmap的工厂类)
Bitmap b = BitmapFactory.decodeResource(getResources(),android.R.drawable.ic_menu_call)
//设置一个大图标
builder.setLargeIcon(b);
//设置通知的声音,震动,呼吸灯为默认系统设置,注意震动需添加权限
builder.setDefaults(Notification.DEFAULT_ALL);
//添加权限在清单文件中:
<uses-permission android:name="android.permission.VIBRATE"/>
builder.setAutoCancel(true); //自动取消通知(需要添加单击事件)
builder.setOngoing(true); //常驻通知,只能在程序在清除
//创建一个通知对象
Notification n = builder.build();
//发送通知需要使用一个系统级的 通知管理器服务 此对象由系统来管理
NotificationManager nm = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID,n);
2、给通知添加单击事件
//-------------给通知添加单击事件---------------
//创建一个意图,(Context,要打开的界面Activity)
Intent intent = new Intent(this,ContentActivity.class);
intent.putExtra("info","新消息:贱贱说:下午请大家吃冰棍儿");
//PendingIntent 延迟的Intent
//PendingIntent.FLAG_UPDATE_CURRENT:
//表示如果PendingIntent已经存在,那么更新内容后使用,没有就创建一个
PendingIntent pi = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pi); //设置内容的意图(Intent)
//在另一个通知事件打开的Activity中获取数据
String info = getIntent().getStringExtra("info");
textView_content.setText(info);
3、添加大视图通知
//添加大视图的样式
NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
style.setBigContentTitle("波波吟诗:");
style.setSummaryText("作者:bobo");
style.addLine("长亭外");
style.addLine("古道边");
style.addLine("一行白鹭上青天");
builder.setStyle(style);
注意,大视图样式在4.1版本后支持,高度为256dp
4、显示进度条下载样式的通知
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentTitle("下载");
builder.setContentText("正在下载中...");
builder.setProgress(100,0,false);//设置进度条(最大值,当前进度,是不是不确定的进度)
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NID_3,builder.build());
new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<=100;i++){
builder.setProgress(100,i,false);
nm.notify(NID_3,builder.build());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
builder.setContentText("下载完成");
nm.notify(NID_3,builder.build());
nm.cancel(NID_3);
}
}).start();
5、自定义通知视图:
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher);//必须设置小图标
//创建一个远程视图对象,目的把该视图添加到系统的通知栏(通知栏属于系统的程序)
RemoteViews views = new RemoteViews(getPackageName(),R.layout.custom_layout);
//为远程视图组件设置图片
views.setImageViewBitmap(R.id.imageView,
BitmapFactory.decodeResource(getResources(),android.R.drawable.ic_dialog_email));
// views.setImageViewResource(R.id.imageView,R.mipmap.ic_launcher);
views.setImageViewResource(R.id.imageButton2_play_pause,
android.R.drawable.ic_media_pause);
// views.setOnClickPendingIntent();//为某一个组件设置单击事件
builder.setContent(views);
PendingIntent pi = PendingIntent.getActivity(
this,0,new Intent(this,ContentActivity.class),0);
builder.setContentIntent(pi);
NotificationManager nm = (NotificationManager) getSystemService(
Context.NOTIFICATION_SERVICE);
nm.notify(NID_4,builder.build());
6、其它(了解一下)
//设置声音
// builder.setDefaults(Notification.DEFAULT_SOUND);
// builder.setSound();
//设置震动
// builder.setDefaults(Notification.DEFAULT_VIBRATE);
// builder.setVibrate(new long[]{0,1000,200,1000});
//设置呼吸灯
// builder.setDefaults(Notification.DEFAULT_LIGHTS);
// builder.setLights(Color.BLUE,1000,1000);
7、小结:在开发应用中通常使用到通知的情况:
<1>普通通知(*****)
<2>自定义通知视频(播放器类的应用中)
用于实现自动提醒功能(例如:新闻消息,短信,消息推送等)
二十五:样式与主题
1、样式
样式是在程序中通一设置一种风格,可以应用在组件上称为样式,应用在Activity上或app上称为主题
在res/values/style.xml文件中定义样式:
例如:
<style name="AppTheme.My">
<item name="colorPrimary">#f77e7e</item>
<item name="colorPrimaryDark">#f43939</item>
<item name="colorAccent">#d1d1d1</item>
</style>
<!--通过parent继承系统的样式-->
<style name="MyTextStyle" parent="@android:style/TextAppearance.DeviceDefault.Medium">
<item name="android:textColor">#454545</item>
<item name="android:textSize">16sp</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
<!--通过上一个样式的 父样式名称.名称 来继承自已的定义的样式 -->
<style name="MyTextStyle.secondTitle">
<item name="android:textColor">#9f9f9f</item>
<item name="android:textSize">12sp</item>
</style>
二十六:自定义组件
自定义组件的三种方式:
<1>、组合现有组件(比如继承一个ViewGroup或布局类)
<2>、继承一个现有的组件进行扩展
<3>、继承View根类完全自定义
1、继承一个组件示例:
<1>自定义属性文件:res/values/attrs.xml文件中定义:
<declare-styleable name="MyCheckBox">
<attr name="value" format="string|reference"></attr>
<attr name="myColor" format="color|reference"></attr>
</declare-styleable>
<2>自定义组件类
public class MyCheckBox extends CheckBox {
private String value;
private int myColor;
//getter and setter...
public MyCheckBox(Context context) {
super(context);
}
public MyCheckBox(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyCheckBox);
//获取属性值
value = array.getString(R.styleable.MyCheckBox_value);
myColor = array.getColor(R.styleable.MyCheckBox_myColor,Color.BLACK);
this.setTextColor(myColor);
//释放
array.recycle();
}
}
<3>在布局文件中使用自定义组件:
引入命名空间
xmlns:app="http://schemas.android.com/apk/res-auto"
<com.moliying.ui_customview.MyCheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/myCheckBox"
android:text="同意协议"
app:value="yes"
app:myColor="@color/colorAccent"
/>
2、通过继承View实现自定义组件
<1>创建一个类继承View,重写构造方法
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
}
//定义自己的属性
private int color;
private String text;
private int textSize;
//getter and setter...
<2>在attrs.xml文件中定义属性:
<declare-styleable name="MyView">
<attr name="textColor" format="color|reference"/>
<attr name="text" format="string|reference"/>
<attr name="textSize" format="integer|reference"/>
</declare-styleable>
<3>在构造方法中获取属性值:
public MyView(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyView);
//获取属性值
textColor = array.getColor(R.styleable.MyView_textColor, Color.BLACK);
text = array.getString(R.styleable.MyView_text);
textSize = array.getInt(R.styleable.MyView_textSize,20);
array.recycle();//释放
}
<4>重写onDraw方法实现绘制
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
p.setColor(textColor);
p.setTextSize(textSize);
p.setStyle(Paint.Style.FILL);// 设置画笔的样式 FILL:实心 STROKE:空心
canvas.drawText(text,10,textSize,p); //绘制文本内容
}
<5>在布局文件中使用自定义组件:
<com.moliying.ui_customview.MyView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:text="非磨砺 不能赢"
app:textColor="@color/colorAccent"
app:textSize="50"
android:layout_below="@+id/button_submit"
android:layout_alignParentStart="true"
android:layout_marginTop="58dp" />
3、解决在ListView/GridView与ScrollView嵌套时的滚动冲突
问题描述:
ListView嵌套ScrollView时,由于ListView的滚动事件会被ScrollView的滚动事件响应,导致
ListView滚动事件无效,会出现ListView内容显示不全的情况,解决方法是重新计算ListView的高度
让所有Item显示出来。
<1>自定义一个类继承ListView,重写计算宽高的方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//重新计算ListView的最大的高度
//makeMeasureSpec(最大值,模式(AT_MOST表示最大数))
heightMeasureSpec = MeasureSpec
.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
<2>在布局文件中使用自定义的ListView即可