android开发--推箱子小游戏(二)

一、前言

迎来第二章的更新啦:使用ListView实现关卡的选择。
本章的内容有点小复杂,毕竟涉及使用了安卓开发中最难用也是最常用的控件之一:ListView
本章可以说是复杂但是单一吧。主要是想大家看完整个系列后收获的不仅仅是照抄照搬代码,最后实现也只实现了一个简简单单的BoxGame。我更希望大家看了之后,能吸收到一些属于自己的东西,最后能实现的是OtherGames ,至少本章能让你熟悉掌握ListView的使用。

二、代码实现

1、ChoiceActivity的布局文件

<?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"
    tools:context=".ChoiceActivity"
    android:orientation="vertical">
    <ListView
        android:id="@+id/lv_mapList"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>

</LinearLayout>

这次我们把Button控件去掉了,换成了一个ListView来实现相同的功能:选择关卡并根据点击的关卡带参数跳转到游戏界面。如果看到这里不是很理解可以回去看看第一章。android开发–推箱子小游戏(一)

2、使用ListView的准备工作

a、新建一个java.class文件(注意:不是新建一个Activity)
业务代码如下:

/*
* 地图名称类
* */
public class ChoiceMapData {
    String MapName;   // 地图名称(即第一关、第二关等)
//    构造函数
    public ChoiceMapData(String MapName){
        this.MapName = MapName;
    }

    public String getMapName() {
        return MapName;
    }

    public void setMapName(String mapName) {
        MapName = mapName;
    }
}

这一个类用通俗的话讲就是ListView数据对象。当我们要新加入第101关的时候,只需要在为ListView添加数据的方法中 new 一个 ChoiceMapData的对象,然后传入参数:“第101关” 即可。
当然传入的参数类型以及个数可以自己在构造方法里面设置。后期的升级改造中会讲到,持续关注哦~

b、新建一个layout文件
在这里插入图片描述布局代码如下

<?xml version="1.0" encoding="utf-8"?>
<!-- 布局格式改为线性布局 -->
<LinearLayout
    android:id="@+id/ly_listItem"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<TextView
    android:id="@+id/tv_mapName"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    android:textSize="25sp"
    android:text="第一关"
    android:gravity="center"/>
</LinearLayout>

这个布局的作用是将TextView放到ListView的条目上显示出来,因为TextView不可能独立于布局之外存在,当然,在放到ListView上的时候,适配器会将这个父布局去掉,留下控件。因为一个界面只能存在一个父布局

3、ListView适配器

新建一个java.class文件,使其继承ArrayAdapter类。
具体代码如下:

/*
* ListView的适配器
* */
public class ChoiceList_adapter extends ArrayAdapter<ChoiceMapData> {
    private int resourceId; // List子项布局的ID
    /*
    * 此方法用于将上下文环境(参数1)、子项布局的ID(参数2)、子项布局的数据(参数3)传递进来
    * */
    public ChoiceList_adapter( Context context, int resource, List<ChoiceMapData> objects) {
        super(context, resource, objects);
        this.resourceId = resource;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;
        ViewHolder viewHolder;
//        获取当前项的ChoiceMapDate的实例
        ChoiceMapData choiceMapData = getItem(position);
//        convertView:用于保存之前加载好的布局(提高 ListView 的运行效率)
        if (convertView == null){
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.mapName = view.findViewById(R.id.tv_mapName);
//            setTag()方法:将ViewHolder内的控件实例缓存到view中
            view.setTag(viewHolder);
        }else {
            view = convertView;
//            getTag()方法:当convertView不为空的时候,把viewHolder重新取出
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.mapName.setText(choiceMapData.getMapName());
        return view;
    }
/*
*用于缓存控件的实例(提高 ListView 的运行效率)
* */
    class ViewHolder{
        TextView mapName;
    }

看完上面的代码如果觉得很复杂,看不懂的话,可以将上面代码的getView()替换掉,换成这个,实现的功能一样,只是效率问题而已。

// 无优化版的ListView的适配器的getVIew方法
     public view getView(int position, View convertView, ViewGroup parent){
   	  ChoiceMapData choiceMapData = getItem(position);
      view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
      TextView mapName = findViewByID(R.id.tv_mapName);
      mapName.setText(choiceMapData.getMapName());
      return view;
     }

4、ChoiceActivity相关代码

/*
* 选择关卡界面
* */
public class ChoiceActivity extends AppCompatActivity {
//    声明ListView控件
    ListView lv_mapList;
//    实例化一个地图选择的列表
    private List<ChoiceMapData> choiceMapDataList = new ArrayList<>();
    Intent intent_mapCode;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_choice);
//        绑定控件
        lv_mapList = findViewById(R.id.lv_mapList);
//        自定义的方法,放入数据
        initChoiceMapDate();
//        参数1:上下问环境;参数2:显示数据的布局;参数3:传入的数据
        final ChoiceList_adapter choiceListAdapter = new ChoiceList_adapter(ChoiceActivity.this,
                R.layout.choicelist_item, choiceMapDataList);
//        设置适配器
        lv_mapList.setAdapter(choiceListAdapter);
        /*
        * 当条目被点击时自动回调
        * */
        intent_mapCode = new Intent(this, GameActivity.class);
        lv_mapList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//                点击条目后携带数据跳转
                intent_mapCode.putExtra("mapCode",position+1);
                startActivity(intent_mapCode);
            }
        });
    }

    /*
    * 利用循环放入数据
    * */
    public void initChoiceMapDate(){
        for (int i=1; i<10; i++){
            ChoiceMapData choiceMapData = new ChoiceMapData("推箱子第" + i + "关");
            choiceMapDataList.add(choiceMapData);
        }
    }
}

ChoiceActivity的代码难度并不大,需要掌握的是Intent的带参跳转。
以下是GameActivity的代码(暂时代码),主要是接收ChoiceActivity传过来的参数,与上章改动不大,需要注意的是参数类型改了。

public class GameActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game);
        getMapCode();
    }

    /*
    * 接收ChoiceActivity传送过来的数据
    * */
    public void getMapCode(){
//        参数1:键值; 参数2:默认值,即没有数据传过来时的值
        int mapCode = getIntent().getIntExtra("mapCode",0);
        if(mapCode == 0){
            Toast.makeText(this, "mapCode为空", Toast.LENGTH_SHORT).show();
            return;
        }
        Toast.makeText(this, ""+mapCode, Toast.LENGTH_SHORT).show();
    }
}

三、总结

这章的内容不多,但是涉及了ListView的使用所以会比较的复杂,但是多练练就可以掌握了。毕竟这个控件还是很常用的,所以花一章的篇幅来讲它,是对它的尊重吧,哈哈。
总而言之,ListView主要有三个准备步骤:
1、新建数据的对象类
2、新建一个layout布局
3、新建ListView的适配器
好了,本章结束。下一章我们讲如何画地图
下章见。
本章最终实现效果
在这里插入图片描述

原创文章 16 获赞 4 访问量 1559

猜你喜欢

转载自blog.csdn.net/weixin_44702572/article/details/103917391
今日推荐