android开发--ListView

ListView与Spinner在代码实现上有些相似,上一篇我写了Spinner,所以我这次写ListView,顺便比较一下这两个控件的不同之处。

android开发--ListViewandroid开发--ListView

 一、简单的一维ListView

效果图:

android开发--ListView

首先,在app/res/values/strings.xml里添加<string-array>来存放我们需要的数据

<string-array name="listViewList">
        <item>红楼梦</item>
        <item>西游记</item>
        <item>水浒传</item>
        <item>三国演义</item>
    </string-array>

方法1:设置entries属性

<ListView
        android:id="@+id/listView"
        android:entries="@array/listViewList"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

方法2:设置ArrayAdapter 

public class MainActivity extends AppCompatActivity {
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        ListView mylistView=findViewById(R.id.listView);
        String[] items=getResources().getStringArray(R.array.listViewList);
        ArrayAdapter<String> myAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,items);
        mylistView.setAdapter(myAdapter);
    }
}

然后添加点击事件:setOnItemClickListener

mylistView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(getApplicationContext(),items[position].toString(),Toast.LENGTH_SHORT).show();
            }
        });

如图所示:

android开发--ListView

二、有文字图片复选框的ListView  (参考来自:ListView的简单应用,这个例子用到了javaBean,是一个很值得借鉴的例子。)

需要实现的ListView效果图如下:

android开发--ListView

首先我们需要创建一个JavaBean来包装我们的数据,新建java class,并取名MyBean.java

如下图设置三个私有变量,然后单击鼠标右键 Generate,点击构造方法Constructor,按住ctrl键点选所有的变量,点击ok插入构造方法。

android开发--ListViewandroid开发--ListViewandroid开发--ListView

同样的添加getter和setter方法,也是选中所有的变量,点击ok就插入了方法。

android开发--ListViewandroid开发--ListView

  MyBean.java 代码如下:

public class MyBean {
    private  int imageID;//商品图片
    private String details;//商品描述
    private  float price;//商品价格

    public MyBean(int imageID, String details, float price) {
        this.imageID = imageID;
        this.details = details;
        this.price = price;
    }

    public int getImageID() {
        return imageID;
    }

    public void setImageID(int imageID) {
        this.imageID = imageID;
    }

    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }
}

然后我们为这个购物清单ListView的列表项设计一个布局,在app/res/layout文件夹下新建一个Layout Resource File,并取名listview_item_layout.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"
    android:id="@+id/L1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <CheckBox
        android:id="@+id/checkBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="110dp"
        android:layout_height="110dp"
        android:padding="5dp"
        app:srcCompat="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/tv_details"
        android:layout_width="150dp"
        android:layout_height="110dp"
        android:padding="5dp"
        android:layout_gravity="center"/>

    <TextView
        android:id="@+id/tv_price"
        android:layout_width="0dp"
        android:layout_height="110dp"
        android:layout_weight="1"
        android:gravity="center"
        android:textStyle="bold" />
</LinearLayout>

修改 activity_main.xml 如下,有一个展示商品的ListView和用来计算购物金额的Button

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="wrap_content"
        android:paddingBottom="34dp">
    </ListView>

    <Button
        android:id="@+id/jiezhang"
        android:layout_gravity="bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="结账离开" />
</FrameLayout>

然后准备我们将要展示的商品数据(商品图片和商品描述)

商品图片复制到app/res/drawable目录下

android开发--ListView

   商品描述写在app/res/values/strings.xml 的<resource>标签里,如下的detailList

<string-array name="detailList">
        <item>宝宝夏装2020新款洋气男孩衣服套装幼儿童装夏季短裙背带裤两件套</item>
        <item>拇指鱼儿童卫衣2019秋季童装拼色长袖T恤套头打底衫小童圆领上衣</item>
        <item>女童套装童装2020夏季新款韩版可爱猫咪蓬蓬裙儿童纱裙公主短裙</item>
        <item>女童洋气网红套装2020新款韩版儿童装短袖两件套女孩时髦运动夏装</item>
        <item>女童连衣裙2020新款夏季洋气装儿童宝宝小孩公主背心裙亲子美女装</item>
        <item>童装男童夏天短袖套装夏装2020新款中大童小儿童网红帅洋气韩版潮</item>
        <item>童装两件套2020夏装女童套装新款夏季女背带裙洋气2短袖衬衫宝宝</item>
        <item>2020卡通动漫新款童装夏牛仔背带裤套装男童短袖t恤潮部落</item>
    </string-array>

为了让我们设计的listview_item_layout.xml、商品的数据与我们在activity_main.xml的ListView适配,我们需要自定义一个Adapter

新建一个Java Class,取名myAdapter.java ,代码如下:

public class myAdapter<T> extends ArrayAdapter {
    private final int resource;
    private Map<Integer,Boolean> map=new HashMap<>();

    public myAdapter(@NonNull Context context, int resource, @NonNull List<MyBean> objects) {
        super(context, resource, objects);
        this.resource=resource;
    }

    @NonNull
    @Override
    public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        
        final MyBean myBean=(MyBean)getItem(position);
        final View view= View.inflate(getContext(),R.layout.listview_item_layout,null);//LayoutInflater.from(getContext()).inflate(resource,parent,null);

        ImageView imageView=view.findViewById(R.id.imageView);
        TextView tv_details=view.findViewById(R.id.tv_details);
        TextView tv_price=view.findViewById(R.id.tv_price);
        final CheckBox checkBox=(CheckBox)view.findViewById(R.id.checkBox);

        imageView.setImageResource(myBean.getImageID());
        tv_details.setText(myBean.getDetails());
        tv_price.setText("¥ "+myBean.getPrice());//以下是为了解决CheckBox状态改变的问题
        checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (checkBox.isChecked()){
                    map.put(position,true);
                }else {
                    map.remove(position);

                }
            }
        });
        if(map!=null&&map.containsKey(position)){
            checkBox.setChecked(true);
        }else {
            checkBox.setChecked(false);
        }
        return view;
    }
}

大家可能奇怪为什么有的代码是红色加粗,其实是为了解决一个CheckBox的问题,如果删掉这段红色代码,也能运行,但是会出现滑动ListView后,勾选的复选框状态改变的问题

复选框状态改变的解决方法参考:Android ListView+CheckBox的实现

 没有加上红色的代码之前:android开发--ListView 加上红色的代码之后:android开发--ListView

写好自定义的Adapter之后,就是最关键的一步了,让数据和ListView适配

  MainActivity.java

public class MainActivity extends AppCompatActivity {

    List<MyBean> myBeans=new ArrayList<>();
    int[] imagesID;//商品图片的id
    String[] detailsID;//商品的描述
    float[] prices;//商品价格
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imagesID= new int[]{R.drawable.clothes1, R.drawable.clothes2, R.drawable.clothes3, R.drawable.clothes4, R.drawable.clothes5, R.drawable.clothes6, R.drawable.clothes7, R.drawable.clothes8};
        detailsID=getResources().getStringArray(R.array.detailList);
        prices= new float[]{78.0f, 160.0f, 67.5f, 188.0f, 189.0f, 79.0f, 38.0f, 68.0f};

        ListView mylistView=findViewById(R.id.listView);
        init();//初始化数据
        myAdapter<String> myAdapter=new myAdapter<String>(this,R.layout.text,myBeans);
        mylistView.setAdapter(myAdapter);
    }

    private void init(){//初始化数据
        int i;
        MyBean item;
        for(i=0;i<imagesID.length;i++){
            item=new MyBean(imagesID[i],detailsID[i],prices[i]);
            myBeans.add(item);
        }
    }
}

到这里为止,我们的购物清单的界面已经完成了,但是别忘了我们还有一个用来结账计算总金额的Button,那么如何得到ListView中复选框选中的项的金额呢?

就要利用CheckBox的setCheckedChangeListener来监听并计算总额

这个监听器就设置在myAdapter的getView()方法里,总金额设为全局变量,在getView方法里的得到CheckBox对象并设置监听器,修改金额,最后加上get方法使其他类可以得到这个计算好的总金额

public class myAdapter<T> extends ArrayAdapter {
   private Map<Integer,Boolean> map=new HashMap<>();
    private float TotalPrice=0;

    public float getTotalPrice() {
        return TotalPrice;
    }

    public myAdapter(@NonNull Context context, int resource, @NonNull List<MyBean> objects) {
        super(context, resource, objects);
    }

    @NonNull
    @Override
    public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        
        final MyBean myBean=(MyBean)getItem(position);
        final View view= View.inflate(getContext(),R.layout.text,null);
        LinearLayout linearLayout=view.findViewById(R.id.L1);
        ImageView imageView=view.findViewById(R.id.imageView);
        TextView tv_details=view.findViewById(R.id.tv_details);
        TextView tv_price=view.findViewById(R.id.tv_price);
        final CheckBox checkBox=(CheckBox)view.findViewById(R.id.checkBox);

        imageView.setImageResource(myBean.getImageID());
        tv_details.setText(myBean.getDetails());
        tv_price.setText("¥ "+myBean.getPrice());
        //以下是为了解决CheckBox的问题
        checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (checkBox.isChecked()){
                    map.put(position,true);
                }else {
                    map.remove(position);

                }
            }
        });
        if(map!=null&&map.containsKey(position)){
            checkBox.setChecked(true);
        }else {
            checkBox.setChecked(false);
        }
        //以下是CheckBox的改变状态触发的事件
        checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked){
                    TotalPrice+=myBean.getPrice();
                }else{
                    TotalPrice-=myBean.getPrice();
                }
            }
        });
        return view;
    }
} 

上面红色的代码就是为CheckBox加的监听器。计算好的总金额会在Button的点击后使用,所以设置get方法得到这个值。

于是我们为Button加一个点击的监听器,下面这段代码写在MainActivity.java的onCreate()方法的最后,从myAdapter对象的get方法得到的金额,用Toast显示。

     Button jiezhang=findViewById(R.id.jiezhang);
        jiezhang.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),String.valueOf(myAdapter.getTotalPrice()),Toast.LENGTH_SHORT).show();
            }
        });

 实现效果如下图所示

android开发--ListView

简单的购物车功能做好啦,其实还有很多值得改进的地方,比如显示添加购买数量的可以加减的组合控件、删除购物清单的商品的按钮、页面跳转、从数据库读取数据啦巴拉巴拉的。