Android学习——UI高级组件一
GridView(网格布局)
GridView是一个在二维可滚动的网格中展示内容的控件。网格中的内容通过使用adapter自动插入到布局中。
1.GridView常用属性与自定义适配器
GridView组件
- 1.自定义适配器
- (1)创建一个类,继承BaseAdapter类
- (2)实现4个方法
- getCount 获取要显示的选项总数
- getItem 获取当前每一个选项
- getItemId 选项ID
- getView 该方法用来为每一个选项生成视图(ImageView),该方法会被多次调用
<GridView
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="auto_fit"
android:columnWidth="90dp"
android:horizontalSpacing="20dp"
android:verticalSpacing="20dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
Activity类中自定义适配器
//自定义适配器(静态内部类)
static class MyAdapter extends BaseAdapter{
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,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher,
R.mipmap.ic_launcher};
private Context context;
public MyAdapter(Context context){
this.context=context;
}
@Override
public int getCount() {
return images.length;
}
@Override
public Object getItem(int position) {
return images[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView iv=new ImageView(context);
iv.setImageResource(images[position]);
return iv;
}
}
调用
private GridView gridView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
gridView =findViewById(R.id.gridView);
//设置适配器
gridView.setAdapter(new MyAdapter(this));
}
2.GridView图文排列
建立一个布局文件,已配置图文排列的样式。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"/>
</LinearLayout>
Activity类中配置适配器
private GridView gridView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
gridView=findViewById(R.id.gridView2);
gridView.setAdapter(new MyAdapter(this));
//点击事件
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//System.out.println("parent="+parent);//GridView的对象
//System.out.println("view="+view);//每一个选项的布局
//System.out.println("position="+position);//所在的位置
//System.out.println("id="+id);//所在的编号值id
TextView tv = view.findViewById(R.id.textView);
Toast.makeText(Main5Activity.this,tv.getText(),Toast.LENGTH_SHORT).show();
}
});
}
//静态内部类
static class MyAdapter extends BaseAdapter{
private String[] names={"转账","查询","金融","基金","国债","信用卡","商场","充值","红包"};
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};
private Context context;
public MyAdapter(Context context){
this.context=context;
}
@Override
public int getCount() {
return names.length;
}
@Override
public Object getItem(int position) {
return names[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//实例化布局
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.item_layout,null);
ImageView iv=view.findViewById(R.id.imageView);
TextView tv=view.findViewById(R.id.textView);
iv.setImageResource(images[position]);
tv.setText(names[position]);
return view;
}
}
- android:columnWidth
相关方法setColumnWidth(int)。定义每一列的固定宽度。
必须是dimension值(浮点数后面拼接单位,例如“14.5sp”)。有效的单位有:px,dp,sp,in,mm。
它也可以是一个资源的引用(@[package:]type:name)或主题属性(?[package:][type:]name)。 - android:gravity
相关方法setGravity(int)。定义每一个单元格的重心。
必须是一个或多个(使用“|”分隔)下面的常量 - android:horizontalSpacing
相关方法setHorizontalSpacing(int)。定义了两列之间的水平间隔。
属性设置要求同android:columnWidth - android:numColumns
相关方法setNumColumns(int)。定义了展示的列数。
可以是一个整形值,如“100”。也可以是一个资源的引用(@[package:]type:name)或主题属性(?[package:][type:]name)。 - android:stretchMode
相关方法setStretchMode(int)。定义了列拓展填充有限闲置空间的方式。 - android:verticalSpacing
相关方法setVerticalSpacing(int)。定义两行之间的垂直间隔。
属性设置要求同android:columnWidth
ListView(列表布局)
1.ListView基本属性配置、ListActivity
- android:dividerHeight=“30dp”//设置listview view之间的高度
- android:divider="@color/colorAccent"//listview view之间的背景或颜色
- android:fadingEdge=“vertical”//上下边有黑色阴影,none的话就没有阴影
- android:cacheColorHint="#000000"//设置拖动背景色为透明
- android:drawSelectorOnTop=“true”//点击某条记录不放时,颜色会记录在后面成为背景色
- android:scrollbars=“horizontal”//只有值为horizontal|vertical时,才会显示滚动条
- android:fastScrollEnabled=“true”//滚动时会有小方块提示
- android:listSelector="@color/design_default_color_primary"//listview选中时的颜色
- android:entries="@array/name"//设置列表填充内容
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:id="@+id/listView"
android:dividerHeight="30dp"
android:divider="@color/colorAccent"
android:fadingEdge="vertical"
android:fastScrollEnabled="true"
android:listSelector="@color/design_default_color_primary"
android:entries="@array/name"/>
Activity中事件设置
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
listView=findViewById(R.id.listView);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView tv= (TextView) view;
Toast.makeText(Main5Activity.this, tv.getText(), Toast.LENGTH_SHORT).show();
}
});
}
选中状态
ListActivity:
不另外配置布局文件,直接在activity文件中进行设置,而且需要修改继承类为ListActivity
public class Main5Activity extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayAdapter<CharSequence> arrayAdapter=ArrayAdapter.createFromResource(
this,R.array.name,android.R.layout.simple_expandable_list_item_1);
setListAdapter(arrayAdapter);
}
//单击事件
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(this, ((TextView)v).getText(), Toast.LENGTH_SHORT).show();
}
2.ListView-单选多选
单选列表
public class Main5Activity extends AppCompatActivity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
listView=(ListView) findViewById(R.id.listView2);
//设置值
String[] arr=getResources().getStringArray(R.array.name);
//单选模式
ArrayAdapter<String> aa=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_single_choice,arr);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setAdapter(aa);
listView=findViewById(R.id.listView2);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView tv= (TextView) view;
Toast.makeText(Main5Activity.this, tv.getText(), Toast.LENGTH_SHORT).show();
}
});
}
多选列表
//多选模式
ArrayAdapter<String> aa2=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_multiple_choice,arr);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setAdapter(aa2);
3.ListView-SimpleAdapter(实现图文列表)
单独定义一个布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="16dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/textView_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="TextView" />
</LinearLayout>
布局样式
改变图文内容
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
listView=findViewById(R.id.listView3);
//准备数据,每一个HashMap作为是一条记录
HashMap<String,Object> title1=new HashMap<>();
title1.put("title","title-1");
title1.put("icon",android.R.drawable.alert_dark_frame);
HashMap<String,Object> title2=new HashMap<>();
title2.put("title","title-2");
title2.put("icon",android.R.drawable.alert_light_frame);
HashMap<String,Object> title3=new HashMap<>();
title3.put("title","title-3");
title3.put("icon",android.R.drawable.arrow_down_float);
//将记录放入list当中
ArrayList<Map<String,String>> list=new ArrayList<>();
list.add(title1);
list.add(title2);
list.add(title3);
//把数据填充到Adapter中(上下文,数据,布局文件,传入上面定义键名称传入对应的值,指定传入的控件id)
SimpleAdapter sa=new SimpleAdapter(this,list,R.layout.list_item,new String[]{"title","icon"},new int[]{R.id.textView_title,R.id.imageView});
listView.setAdapter(sa);
}
4.ListView-自定义适配器(BaseAdapter)
BaseAdapter 自己进行控制,更加灵活
建立一个listview
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:id="@+id/listView4"/>
新建布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="16dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/textView_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="TextView" />
</LinearLayout>
Activity中设置BaseAdapter
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
listView=findViewById(R.id.listView4);
listView.setAdapter(new MyAdapter(this));
}
static class MyAdapter extends BaseAdapter{
//文字列表
private String[] titles={"title-1","title-2","title-3","title-4","title-5"};
//图片列表
private int[] icons={android.R.drawable.ic_dialog_email,
android.R.drawable.ic_delete,
android.R.drawable.ic_input_add,
android.R.drawable.ic_dialog_info,
android.R.drawable.ic_dialog_map};
//构造方法
private Context context;
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) {
LayoutInflater inflater=LayoutInflater.from(context);
View view = inflater.inflate(R.layout.list_item,null);
TextView tv_title=view.findViewById(R.id.textView_title);
ImageView iv_icon=view.findViewById(R.id.imageView);
tv_title.setText(titles[position]);
iv_icon.setImageResource(icons[position]);
return view;
}
}
}
5.优化ListVew(避免浪费内存)
- ListView的宽高要相对固定
避免内容变化到时ListView 重新渲染 - 重复使用convertView:
convertView为空闲可用的对象,是一个作为缓存的view,通过使用这个缓存可以替换掉用Inflater加载组件这一步,也是通过重复利用这个对象,以避免重复创建对象,减少内存的消耗。
具体使用代码如下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//党convertView为空时,才实例化view
if (convertView==null){
LayoutInflater inflater=LayoutInflater.from(context);
//实例化一个布局文件
convertView = inflater.inflate(R.layout.list_item,null);
}
TextView tv_title=convertView.findViewById(R.id.textView_title);
ImageView iv_icon=convertView.findViewById(R.id.imageView);
tv_title.setText(titles[position]);
iv_icon.setImageResource(icons[position]);
return convertView;
}
- 使用ViewHolder提高在容器中查找组件的效率:
convertView和ViewHolder一起用;ViewHolder中持有的组件和converView中的组件指向同一个对象,所以这里使用ViewHolder就是替换掉findViewById,减少对象的查找
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh = null;
//当convertView为空时,才实例化view
if (convertView==null){
LayoutInflater inflater=LayoutInflater.from(context);
//实例化一个布局文件
convertView = inflater.inflate(R.layout.list_item,null);
vh=new ViewHolder();
vh.iv_icon=convertView.findViewById(R.id.imageView);
vh.tv_title=convertView.findViewById(R.id.textView_title);
convertView.setTag(vh);
}else{
vh= (ViewHolder) convertView.getTag();
}
vh.tv_title.setText(titles[position]);
vh.iv_icon.setImageResource(icons[position]);
return convertView;
}
//内部类,用于保存第一次查找的组件,避免下一次重复查找
static class ViewHolder{
ImageView iv_icon;
TextView tv_title;
}
6.ListView分页
新建一个News类
public class News {
String title;
String content;
}
设置加载状态的布局文件
loadin.xml
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="正在玩命加载中。。。" />
设置ListView
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:id="@+id/listView5"/>
在Activity类中
/*
* 分页
* */
public class Main6Activity extends AppCompatActivity implements AbsListView.OnScrollListener {
private ListView listView;
private Vector<News> news=new Vector<>();//容器,装对象
private MyAdapter myAdapter;
private static final int DATA_UPDATE=0x1;//数据更新完成后的标记
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main6);
listView=findViewById(R.id.listView5);
//注册滚动条事件
listView.setOnScrollListener(this);
View footerView=getLayoutInflater().inflate(R.layout.loading,null);
listView.addFooterView(footerView);
initDate();
myAdapter = new MyAdapter();
listView.setAdapter(myAdapter);
}
private int index=1;
/*
* 初始化数据
* */
private void initDate(){
for (int i=0;i<10;i++){
News n=new News();
n.title="title--"+index;
n.content="content--"+index;
index++;
news.add(n);
}
}
private int visibleLastIndex;//用来可显示的最后一条数据的索引值
@Override//滚动状态改变的方法
public void onScrollStateChanged(AbsListView view, int scrollState) {
//滚动事件,停止状态
if (myAdapter.getCount()==visibleLastIndex&&scrollState== AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
new LoadDateThread().start();
}
}
@Override//滚动的方法
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
visibleLastIndex=firstVisibleItem+visibleItemCount-1;
}
//线程之间进行通讯的机制 Hander(处理器) 处理消息用
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case DATA_UPDATE:
myAdapter.notifyDataSetChanged();
break;
}
}
};
//模拟加载数据的线程
class LoadDateThread extends Thread{
@Override
public void run() {
initDate();
try {
Thread.sleep(2000);//休眠两秒
} catch (InterruptedException e) {
e.printStackTrace();
}
//通过Handler给主线程发送一个消息标记
handler.sendEmptyMessage(DATA_UPDATE);
}
}
//自定义适配器填充数据
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return news.size();
}
@Override
public Object getItem(int position) {
return news.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh;
if (convertView==null){
convertView=getLayoutInflater().inflate(R.layout.list_item,null);
vh=new ViewHolder();
vh.tv_title=convertView.findViewById(R.id.textView_title);
vh.tv_content=convertView.findViewById(R.id.textView_content);
convertView.setTag(vh);
}else{
vh= (ViewHolder) convertView.getTag();
}
News n=news.get(position);
vh.tv_title.setText(n.title);
vh.tv_content.setText(n.content);
return convertView;
}
class ViewHolder{
TextView tv_title;
TextView tv_content;
}
}
}