一、前言
利用android的ListView组件开发,类似于苹果手机的“系统设置”页面,达到ListView子项item包含图标,文字说明,以及子项item分组具有突出显示的效果。下文会有效果的展示以及开发流程。
二、效果图
三、开发步骤&源代码
3.1、添加ListView控件
首先新建一个ListView项目,并让Android Studio自动帮我们创建好活动,然后修改activity_main.xml的代码,如下所示。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorGray">
<LinearLayout android:id="@+id/line1"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="20dp"
android:background="@android:color/white">
<!--并不能够通过添加两个ListView,来达到在一个activity中放置两个ListView的预期效果,
会导致丧失ListView原有的滚动效果,因为两个ListView相互独立,只有一个ListView会滚动
而不是两个作为整体滚动。 -->
<ListView
android:id="@+id/system_setting_list_view_1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</RelativeLayout>
外层是相对布局RelativeLayout,并设置背景颜色RGB为#E5E5E5,背景色的RGB值放置在资源文件“app/res/values/colors.xml”中。
内存为线性布局LinearLayout,并设置背景色white, 通过对背景色的设置就达到了突出显示。
值得说明的是在内层的线性布局中,利用android:layout_alignParentTop属性,让内层布局置顶;利用android:layout_marginTop=”20dp”属性,将内层线性布局与标题分隔20dp。
3.2、定义实体类
定义一个实体类SystemSettingItem,作为ListView适配器(adapter)的适配类型。
public class SystemSettingItem {
private String SystemSettingName;
private int ImageId;
// ... 省略了构造函数,以及get,set方法
}
SystemSettingName: 系统设置项的名称,类似于“飞行模式”。
ImageId:系统设置项图标的id, 图标资源文件放置在/app/res/drawable-hdpi目录下
这里指的注意的是,我们给png图片起的文件名并不是数字,为什么ImageId为int类型的数据。这是因为我们引用png图片的方式为imageView.setImageResource(R.drawable.flight_mode);“R.drawable.flight_mode”,这是一个由系统自动为我们生成的整型数据。
3.3、ListView子项布局
为ListView子项指定一个我们自定义的布局,在app/res/layout目录下新建一个system_setting_item.xml。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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/image_id"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentLeft="true"
android:layout_margin="10dp"/>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/image_id"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"/>
<ImageView android:id="@+id/enter_id"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentRight="true"
android:layout_margin="10dp"/>
</RelativeLayout>
这里之所以采用相对布局的方式,是为了达到让“进入图标”能够在最右边显示的效果,相对于线性布局,相对布局更容易实现。
ImageView - android:layout_alignParentLeft=”true” : 让图标视图处于ListView子项的最左边。
TextView - android:layout_toRightOf=”@id/image_id” : 让文本处于图标的右边
Image-View : android:layout_alignParentRight=”true” : 让“进入”图标处于ListView空间子项的最右边。
3.4、自定义适配器
接下来创建一个自定义适配器SystemSettingAdapter,这个适配器继承自ArrayAdapter,指定泛型为SystemSettingItem。
package com.dmw.adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.dmw.activity.R;
import com.dmw.domain.SystemSettingItem;
import java.util.List;
public class SystemSettingAdapter extends ArrayAdapter<SystemSettingItem> {
private int resourceId;
private Context context;
/**
*
* @param context :MainActivity.this 活动的上下文
* @param resource :R.layout.system_setting_item 自定义的ListView子项
* @param objects :ssiList 自定义的实体类数组
*/
public SystemSettingAdapter(@NonNull Context context, int resource, @NonNull List<SystemSettingItem> objects) {
super(context, resource, objects);
resourceId = resource;
this.context = context;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
// 获得当前项的实例,position为子项Item在ListView空间中的顺序编号
SystemSettingItem ssi = getItem(position);
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
// 模拟分割,将ListView中的一项item设置背景颜色为gray
if(ssi.getSystemSettingName().equals("line")){
// 获取自定义资源文件中的颜色值(int)
view.setBackgroundColor(context.getResources().getColor(R.color.colorGray));
return view;
}
// 设置列表项内容
ImageView imageView = (ImageView)view.findViewById(R.id.image_id);
imageView.setImageResource(ssi.getImageId());
TextView textView = (TextView)view.findViewById(R.id.name);
textView.setText(ssi.getSystemSettingName());
ImageView enterView = (ImageView)view.findViewById(R.id.enter_id);
enterView.setImageResource(R.drawable.enter);
return view;
}
}
为了实现ListView控件子项的分组,曾采用过在一个Activity活动页面添加两个独立的ListView控件的方式,但是由于两个控件相互独立,在页面滑动的过程中,展现的效果不是整体的滑动效果,另人尴尬。
所以这里采用的是,将一个ListView中名为”line”的一个子项,将他的背景色设置为布局的背景色,不添加图标和文字,也不添加点击事件,只作为分割线使用。
3.5、MainActivity
package com.dmw.activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.dmw.adapter.SystemSettingAdapter;
import com.dmw.domain.SystemSettingItem;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<SystemSettingItem> ssiList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 只是为了展示滚动效果,所以让数量*2
for(int i = 0;i < 2;i++)
initSsiList();
// 借助适配器将数据传递给ListView
SystemSettingAdapter adapter = new SystemSettingAdapter(MainActivity.this, R.layout.system_setting_item, ssiList);
ListView listView = findViewById(R.id.system_setting_list_view_1);
listView.setAdapter(adapter);
// 设置ListView中子项item的点击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SystemSettingItem ssi = ssiList.get(position);
if(!ssi.getSystemSettingName().equals("line"))
Toast.makeText(MainActivity.this, ssi.getSystemSettingName(), Toast.LENGTH_SHORT).show();
}
});
}
/**
* ListView子项item数据初始化
*/
private void initSsiList(){
SystemSettingItem flightMode = new SystemSettingItem("飞行模式", R.drawable.flight_mode);
ssiList.add(flightMode);
SystemSettingItem wlan = new SystemSettingItem("无线局域网", R.drawable.wlan);
ssiList.add(wlan);
SystemSettingItem blueTooth = new SystemSettingItem("蓝牙", R.drawable.blue_tooth);
ssiList.add(blueTooth);
SystemSettingItem cellular = new SystemSettingItem("蜂窝移动网络", R.drawable.cellular);
ssiList.add(cellular);
SystemSettingItem hotspot = new SystemSettingItem("个人热点", R.drawable.hotspot);
ssiList.add(hotspot);
SystemSettingItem operator = new SystemSettingItem("运营商", R.drawable.operator);
ssiList.add(operator);
ssiList.add(new SystemSettingItem("line", 0));
SystemSettingItem inform = new SystemSettingItem("通知", R.drawable.inform);
ssiList.add(inform);
SystemSettingItem console = new SystemSettingItem("控制中心", R.drawable.console);
ssiList.add(console);
SystemSettingItem moon = new SystemSettingItem("勿扰模式", R.drawable.moon);
ssiList.add(moon);
ssiList.add(new SystemSettingItem("line", 0));
}
}