【从零到一】Android UI界面(三) | 适配器控件篇

目录

  • 1. ListView(列表)
  • 2. Spinner(下拉列表)
  • 3. GridView(网格视图)
  • 4. ViewPager(视图滑动切换工具)


  这篇文章我们将重点介绍ListView控件,并介绍 适配器(Adapter) 的使用,适配器的作用是将复杂的数据填充在指定的视图界面上 ,这么说可能不太明白,下面我们会详细介绍,本篇介绍的控件包括:

  1. ListView(列表)
  2. Spinner(下拉列表)
  3. GridView(网格视图)
  4. ViewPager(试图滑动切换工具)

1. ListView(列表)

   ListView 以列表的形式展示数据,需要用到 适配器 搭建数据源和视图界面的桥梁。如果是单一的数据,可使用ArrayAdapter适配器加载数据。我们需要把数据加载到适配器中,再将适配器绑定给ListView,具体步骤如下:

  1. 创建ListView控件;
  2. 准备数据源;
  3. 适配器绑定数据源;
  4. ListView控件绑定适配器;

   实例:

  1. 创建ListView控件;

activity_main.xml

<?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="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="#00000000"></ListView>


</LinearLayout>
  1. 准备数据源,适配器绑定数据源,ListView控件绑定适配器;

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private ArrayAdapter<String> adapter;//适配器


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView = findViewById(R.id.listView);

        String data[] ={"apple","banana","watermelon","pear","peach"};//数据源
        adapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,data);//适配器绑定数据源
        listView.setAdapter(adapter);//ListView绑定适配器
    }
}

ArrayAdapter<>(this,android.R.layout.simple_list_item_1,data); 3个参数分别是:

  • context:上下文
  • LayoutRes:列表项布局(此处使用系统提供的布局)
  • 数据源

   效果:
【从零到一】Android UI界面(三) | 适配器控件篇_第1张图片
   是不是挺简单的,这里提出一个问题:怎么让ListView中的每一项具有点击事件呢? 这里依旧用到我们上篇文章介绍Button时学到的 监听器,ListView的监听器是 OnItemClickListener ,监听器中的 int类型参数 position 表示点击项为第几项(从0数起)。

MainActivity.java

        //监听器
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String text = listView.getItemAtPosition(position)+"";//getItemAtPosition()方法用于获取被点击项的内容
                Toast.makeText(MainActivity.this, position +" , "+ text,Toast.LENGTH_SHORT).show();
            }
        });

   效果:
【从零到一】Android UI界面(三) | 适配器控件篇_第2张图片
  上面的实例中,列表项是单一的数据,如果我们要实现每个列表项由 图片+文字内容 组成呢?能不能做到呢?答案是肯定的,这里我们只需要自定义我们的列表项布局,自定义适配器即可,步骤如下:

  1. 创建一个列表项布局;
  2. 创建一个实体类(作为适配器的适配类型);
  3. 创建一个适配器继承自ArrayAdapter,重写方法;

实例如下:

  1. 创建一个列表项布局

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <ImageView
        android:id="@+id/imageView"
        android:src="@mipmap/ic_launcher"
        android:layout_width="100dp"
        android:layout_height="100dp" />
    <TextView
        android:id="@+id/textView2"
        android:text="fruit"
        android:textSize="40dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>
  1. 创建一个实体类(作为适配器的适配类型)

Fruit.java

public class Fruit {
    private String name;
    private int imageid;

    public Fruit(int imageid, String name){
        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;
    }
}
  1. 创建一个适配器继承自ArrayAdapter,重写方法

FruitAdapter .java

public class FruitAdapter extends ArrayAdapter<Fruit> {
    private int itemLayout;

    public FruitAdapter(Context context, int resource, List<Fruit> objects) {
        super(context, resource, objects);
        itemLayout = resource;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //1.获取列表项的实例
        Fruit fruit = getItem(position);
        //2.设置列表项的布局
        View view = LayoutInflater.from(getContext()).inflate(itemLayout,null);
        //3.绑定控件实例
        ImageView imageView = view.findViewById(R.id.imageView);
        TextView textView = view.findViewById(R.id.textView2);
        imageView.setImageResource(fruit.getImageid());
        textView.setText(fruit.getName());
        return view;
    }
}
  1. 在MaineActivity中创建数据源,加载到适配器中,再把适配器绑定到ListView中
public class Main2Activity extends AppCompatActivity {
    private ListView listView;
    private FruitAdapter fruitAdapter;
    private List<Fruit> list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        listView = findViewById(R.id.listView2);
        //1.数据源
        list = new ArrayList<>();//创建list实例
        listinit();
        //2.适配器绑定数据源
        fruitAdapter = new FruitAdapter(Main2Activity.this,R.layout.item,list);
        //3.ListView绑定适配器
        listView.setAdapter(fruitAdapter);
    }

    private void listinit() {
        int image[] = {R.drawable.apple,R.drawable.banana,R.drawable.watermelon,R.drawable.pear,R.drawable.peach};
        String data[] ={"apple","banana","watermelon","pear","peach"};
        for (int i=0;i<5;i++){
            Fruit fruit = new Fruit(image[i],data[i]);
            list.add(fruit);
        }
    }
}

  效果:
【从零到一】Android UI界面(三) | 适配器控件篇_第3张图片
  这样一来我们就实现了复杂的列表项,看似完美其实还是有地方可以优化的。FruitAdapter.java的getView()会在每获取一个列表项时就执行一次,而我们在该方法中执行了一下代码:

 		//设置列表项的布局
        View view = LayoutInflater.from(getContext()).inflate(itemLayout,null);
        //绑定控件实例
        ImageView imageView = view.findViewById(R.id.imageView);
        TextView textView = view.findViewById(R.id.textView2);

  这就意味着我们每获取一个列表项都需要重新加载一遍布局,这种做法相当低效。因此,我们把显示过的item View缓存起来,下次使用时直接复用就能提高LIstView的运行效率了,优化后的代码如下:

FruitAdapter.java

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //1.获取列表项的实例
        Fruit fruit = getItem(position);
        View view;

        ViewHolder viewHolder;
        if (convertView == null){
            //2.设置列表项的布局
            view = LayoutInflater.from(getContext()).inflate(itemLayout,null);
            //3.绑定控件实例
            viewHolder = new ViewHolder();
            viewHolder.imageView = view.findViewById(R.id.imageView);
            viewHolder.textView = view.findViewById(R.id.textView2);
            view.setTag(viewHolder);
        }else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();
        }

        viewHolder.imageView.setImageResource(fruit.getImageid());
        viewHolder.textView.setText(fruit.getName());
        return view;
    }
    class ViewHolder{
        ImageView imageView;
        TextView textView;
    }

2. Spinner(下拉列表)

  Spinner是下拉列表,使用类似于ListView,监听器为 OnItemSelectedListener ,使用步骤如下:

  1. 创建Spinner控件
  2. 创建下拉列表数据源
  3. 创建适配器,适配器绑定数据源
  4. Spinner绑定适配器
  5. 给Spinner添加监听器

实例:

activity_spinner.xml

<?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="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".SpinnerActivity">
    <TextView
        android:id="@+id/textView3"
        android:text="今天打算吃什么水果?"
        android:textSize="30dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <Spinner
        android:id="@+id/spinner"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></Spinner>

</LinearLayout>

SpinnerActivity.java

public class SpinnerActivity extends AppCompatActivity {
    private TextView textView;
    private Spinner spinner;
    private List<String> fruitList;
    private ArrayAdapter<String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_spinner);
        textView = findViewById(R.id.textView3);
        spinner = findViewById(R.id.spinner);
        //1.数据源
        fruitList = new ArrayList<>();
        init();
        //2.适配器
        adapter = new ArrayAdapter<>(this,android.R.layout.simple_spinner_item,fruitList);
        //选择下拉列表样式
        adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
        //3.Spinner绑定适配器
        spinner.setAdapter(adapter);
        //4.Spinner添加监听器
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                String fruitName = adapter.getItem(position);
                textView.setText("今天打算吃"+ fruitName);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
    }

    private void init() {
        String data[] ={"apple","banana","watermelon","pear","peach"};
        for (int i=0;i<5;i++){
            fruitList.add(data[i]);
        }
    }
}

效果:
【从零到一】Android UI界面(三) | 适配器控件篇_第4张图片


3. GridView(网格视图)

  GridView是网格视图,属于网格版的ListVIew,监听器跟LIstView一样使用的是 OnItemClickListener,先来了解一下GridView特有的属性吧:

  • android:verticalSpacing(两列之间的间距)
  • android:horizontalSpacing(两行之间的间距)
  • android:numColumns(每行显示多少列,选值为 auto_fit 表示自适应)

  我们这里使用另一种适配器 SimpleAdapter 来写一个简单的例子,步骤基本跟ListView一样,这里主要学习一下SimpleAdapter 的使用方法,具体步骤如下:

  1. 创建GridView控件
  2. 创建数据源
  3. 数据源绑定适配器
  4. GridView绑定适配器
  5. GridView添加监听器

实例:

  1. 创建GridView控件
    <GridView
        android:id="@+id/gridView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:horizontalSpacing="20dp"
        android:verticalSpacing="20dp"
        android:layout_marginTop="20dp"
        android:numColumns="2"></GridView>
  1. 创建数据源
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_grid_view);
        gridView = findViewById(R.id.gridView);
        //2.准备数据源
        fruitList = new ArrayList<>();
        listinit();
    }

    private void listinit() {
        int image[] = {R.drawable.apple,R.drawable.banana,R.drawable.watermelon,R.drawable.pear,R.drawable.peach};
        String data[] ={"apple","banana","watermelon","pear","peach"};
        for (int i=0;i<data.length;i++){
            Map<String,Object> map = new HashMap<>();
            map.put("image",image[i]);
            map.put("data",data[i]);
            fruitList.add(map);
        }
    }
  1. 数据源绑定适配器
        //3.适配器绑定数据源
        simpleAdapter = new SimpleAdapter(GridViewActivity.this,fruitList,R.layout.item2,new String[]{"image","data"},new int[]{R.id.imageView2,R.id.textView3});

  1. GridView绑定适配器
        //4.GridView绑定适配器
        gridView.setAdapter(simpleAdapter);
  1. GridView添加监听器
        //5.给GridView添加监听器
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(GridViewActivity.this,position+":"+ data[position],Toast.LENGTH_SHORT).show();
            }
        });

效果:
【从零到一】Android UI界面(三) | 适配器控件篇_第5张图片


4. ViewPager(视图滑动切换工具)

  ViewPager是视图滑动切换工具,是如今应用相当广泛的一个控件,ViewPager的 监听器OnPageChangeListener。这里通过一个简单实例来介绍如何使用ViewPager,和介绍一个新的 适配器 PagerAdapter,具体步骤如下:

  1. 创建ViewPager控件(内部包含一个PagerTabStrip标签)
    <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/pagerTabStrip"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        </android.support.v4.view.PagerTabStrip>
    </android.support.v4.view.ViewPager>
  1. 创建数据源
public class ViewPagerActivity extends AppCompatActivity {
    private ViewPager viewPager;
    private PagerTabStrip pagerTabStrip;
    private List<View> viewList;
    private List<String> titleList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_pager);
        viewPager = findViewById(R.id.viewPager);
        pagerTabStrip = findViewById(R.id.pagerTabStrip);
        viewList = new ArrayList<>();
        titleList = new ArrayList<>();
        //2.准备数据源(需要手动创建4个简单的布局文件)
        View view1 = View.inflate(this,R.layout.page1,null);
        View view2 = View.inflate(this,R.layout.page2,null);
        View view3 = View.inflate(this,R.layout.page3,null);
        View view4 = View.inflate(this,R.layout.page4,null);
        viewList.add(view1);
        viewList.add(view2);
        viewList.add(view3);
        viewList.add(view4);
        titleList.add("第一页");
        titleList.add("第二页");
        titleList.add("第三页");
        titleList.add("第四页");
	}
}
  1. 创建PagerAdapter适配器
public class MyPagerAdapter extends PagerAdapter {
    //数据源
    private List<View> viewList;
    private List<String> titleList;

    MyPagerAdapter(List<View> viewList,List<String> titleList){
        this.viewList = viewList;
        this.titleList = titleList;
    }
    @Override
    public int getCount() {
        return viewList.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object o) {
        return view == o;
    }

    /**
     * 实例化一个页卡
     * @param container
     * @param position
     * @return
     */
    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        container.addView(viewList.get(position));
        return viewList.get(position);
    }

    /**
     * 销毁一个页卡
     * @param container
     * @param position
     * @param object
     */
    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        container.removeView(viewList.get(position));
    }

    /**
     * 返回页卡标题信息
     * @param position
     * @return
     */
    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        return titleList.get(position);
    }
}

  1. 创建PagerAdapter适配器,绑定数据源
        //4.创建PagerAdapter适配器,绑定数据源
        MyPagerAdapter myPagerAdapter = new MyPagerAdapter(viewList,titleList);
  1. ViewPager绑定适配器
        //5.ViewPager绑定适配器
        viewPager.setAdapter(myPagerAdapter);
  1. ViewPager添加监听器
        //6.ViewPager添加监听器
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i1) {

            }

            @Override
            public void onPageSelected(int i) {
                Toast.makeText(ViewPagerActivity.this,"第"+(i+1)+"页",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });
  1. 我们还可以为pagerTabStrip修改样式
        pagerTabStrip.setBackgroundColor(Color.GRAY);
        pagerTabStrip.setTextColor(Color.BLACK);
        pagerTabStrip.setTabIndicatorColor(Color.RED);

让我们运行看看效果吧:
【从零到一】Android UI界面(三) | 适配器控件篇_第6张图片


  至此我们学习了四个适配器控件,接下来的文章会继续介绍更多高级控件,感谢阅读。

  Github项目地址:AdapterWidget

你可能感兴趣的:(UI界面,从零到一)