Android:日常学习笔记(8)———探究UI开发(5)
ListView控件的使用
ListView概述
A view that shows items in a vertically scrolling list. The items come from the ListAdapter
associated with this view.
1.关于ArrayAdapter:
ArrayAdapter<T> 是 ListAdapter的直接子类:一个由任意对象数组支持的具体的BaseAdapter。
一个支持任意对象数组的具体的BaseAdapter。默认情况下,这个类期望提供的资源id引用一个TextView。如果你使用更加复杂的布局, 使用需要字段id的构造函数。 That field id should reference a TextView in the larger layout resource.
However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.
To use something other than TextViews for the array display, for instance, ImageViews, or to have some of data besides toString() results fill the views, override
getView(int, View, ViewGroup)
to return the type of view you want.
2.关于getView(int, View, ViewGroup)
获得一个可以在指定位置显示数据集中数据的视图。你可以手动创作一个视图也可以加载XML中的视图。 When the View is inflated, the parent View (GridView, ListView...) will apply default layout parameters unless you use
inflate(int, android.view.ViewGroup, boolean)
to specify a root view and to prevent attachment to the root.
ListView的简单用法
public class MainActivity extends AppCompatActivity { private String[] data={"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry",
"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry",
"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ArrayAdapter<String> adapter = new ArrayAdapter<String>
(MainActivity.this,R.layout.support_simple_spinner_dropdown_item,data); ListView listView = (ListView) findViewById(R.id.list_view); listView.setAdapter(adapter); } }
说明:
ArrayAdapter通过泛型来指定要适配的数据类型,然后在构造函数中把当前上下文、ListView子项布局的ID、要适配的数据传入。
我们在这里使用了安卓的内置布局文件。
ListView设置适配器,setAdapter(),将构建好的适配器对象传进去,以此建立数据与ListView之间的关系。
定制ListView界面
1.定义一个实体类
public class Fruit { private String name; private int imageID; public Fruit(String name, int imageID) { this.name = name; this.imageID = imageID; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getImageID() { return imageID; } public void setImageID(int imageID) { this.imageID = imageID; } }
2.自定义子项布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/fruit_img" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/fruit_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp"/> </LinearLayout>
3.编写适配类
public class FruitAdapter extends ArrayAdapter<Fruit> { private int resourceID; public FruitAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull List<Fruit> objects) { super(context, resource, textViewResourceId, objects); resourceID = textViewResourceId; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Fruit fruit = getItem(position); View view = LayoutInflater.from(getContext()).inflate(resourceID,parent,false); ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_img); TextView fruitText = (TextView) view.findViewById(R.id.fruit_text); fruitImage.setImageResource(fruit.getImageID()); fruitText.setText(fruit.getName()); return view; } }
4.应用
public class MainActivity extends AppCompatActivity { private List<Fruit> fruitList=new ArrayList<>(); protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initFruits(); FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.activity_main,R.layout.entry_fruit_item,fruitList); ListView listView = (ListView) findViewById(R.id.list_view); listView.setAdapter(adapter); } public void initFruits() { for(int i=0;i<100;i++) { fruitList.add(new Fruit("XXX",R.drawable.next_24px)); } } }
提升ListView的运行效率
1.避免重复加载布局文件
在getView中加入如下代码:
//convertView用于将之前加载好的布局进行缓存,这里进行判断,避免重复加载。 if(convertView==null) view = LayoutInflater.from(getContext()).inflate(resourceID,parent,false); else view =convertView;
2.避免重复查找控件
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Fruit fruit = getItem(position); View view; ViewHolder viewHolder; //convertView用于将之前加载好的布局进行缓存,这里进行判断,避免重复加载。 if(convertView==null) { view = LayoutInflater.from(getContext()).inflate(resourceID,parent,false); viewHolder= new ViewHolder(); viewHolder.fruitImage=(ImageView) view.findViewById(R.id.fruit_img); viewHolder.fruitText=(TextView) view.findViewById(R.id.fruit_text); view.setTag(viewHolder); } else { view =convertView; viewHolder= (ViewHolder) view.getTag(); } viewHolder.fruitImage.setImageResource(fruit.getImageID()); viewHolder.fruitText.setText(fruit.getName()); return view; }
//用于对控件的实例进行缓存 class ViewHolder{ ImageView fruitImage; TextView fruitText; } }
ListView的点击事件
FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.activity_main,R.layout.entry_fruit_item,fruitList); ListView listView = (ListView) findViewById(R.id.list_view); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Fruit fruit = fruitList.get(position); Toast.makeText(MainActivity.this,fruit.getName(),Toast.LENGTH_LONG).show(); } });
RecyclerView
使用RecyclerView
1.在build.gradle添加相应的依赖库
2.点击Sync Now进行同步。
3.修改XML布局文件
简单使用
1.编写适配器
public class FruitRecyclerAdapter extends RecyclerView.Adapter<FruitRecyclerAdapter.viewHolder> { private List<Fruit> fruitList; static class viewHolder extends RecyclerView.ViewHolder { ImageView fruitImage; TextView fruitText; public viewHolder(View itemView) { super(itemView); fruitImage = (ImageView) itemView.findViewById(R.id.fruit_img); fruitText = (TextView) itemView.findViewById(R.id.fruit_text); } } @Override public viewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.entry_fruit_item,parent,false); viewHolder viewHolder = new viewHolder(view); return viewHolder; } //在每一个子项被滚动到屏幕内时执行 @Override public void onBindViewHolder(viewHolder holder, int position) { Fruit fruit = fruitList.get(position); holder.fruitText.setText(fruit.getName()); holder.fruitImage.setImageResource(fruit.getImageID()); } @Override public int getItemCount() { return fruitList.size(); } public FruitRecyclerAdapter(List<Fruit> fruitList) { this.fruitList = fruitList; } }
2.应用
public class RecyclerListActivity extends AppCompatActivity { private List<Fruit> fruitList =new ArrayList<>(); protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initData(); setContentView(R.layout.activity_recycler_list); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycle_view); LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); FruitRecyclerAdapter fruitRecyclerAdapter = new FruitRecyclerAdapter(fruitList); recyclerView.setAdapter(fruitRecyclerAdapter); } public void initData() { for(int i=0;i<30;i++) { Fruit fruit = new Fruit("XXX",R.drawable.next_24px); fruitList.add(fruit); } } }
实现横向滚动
1.修改布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="100dp" android:layout_height="wrap_content" android:orientation="vertical"> <ImageView android:id="@+id/fruit_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/next_24px" android:layout_gravity="center_horizontal"/> <TextView android:id="@+id/fruit_text" android:text="XXXXX" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> </LinearLayout>
效果如右图所示:
2.在布局管理器中设置布局排布方式为水平
。。。 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initData(); setContentView(R.layout.activity_recycler_list); RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycle_view); LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerView.setLayoutManager(layoutManager); FruitRecyclerAdapter fruitRecyclerAdapter = new FruitRecyclerAdapter(fruitList); recyclerView.setAdapter(fruitRecyclerAdapter); } 。。。
说明:
ListView的布局排列规则是由自己管理的,而RecyclerView则将这个工作交给了布局管理器,LayoutManager中置顶了一套可扩展的布局排列接口,子类只要按照接口的规范来实现,就能制定出各种不同排列方式的布局了。
瀑布流布局
效果:
代码:
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager);
处理点击事件
public viewHolder onCreateViewHolder(final ViewGroup parent, int viewType) { View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.entry_fruit_vertical_item,parent,false); final viewHolder viewHolder = new viewHolder(view); viewHolder.fruitView.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { int position = viewHolder.getAdapterPosition(); Fruit fruit = fruitList.get(position); Toast.makeText(parent.getContext(),fruit.getName(),Toast.LENGTH_LONG).show(); } }); return viewHolder; }
说明:
RecyclerView的强大之处在于,他可以轻松实现子项中任意控件或布局的点击事件。