UI 基本组件 笔记 待整理

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即可







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值