Android-PickerView 轻量级选择器:WheelView 基础控件使用指南

Android-PickerView 轻量级选择器:WheelView 基础控件使用指南

【免费下载链接】Android-PickerView This is a picker view for android , support linkage effect, timepicker and optionspicker.(时间选择器、省市区三级联动) 【免费下载链接】Android-PickerView 项目地址: https://gitcode.com/gh_mirrors/an/Android-PickerView

引言:解决Android选择器的痛点

你是否还在为Android原生Spinner控件的单调外观和有限功能而困扰?是否需要一个高性能、可定制的滚轮选择控件来实现时间选择、省市区联动等复杂交互?Android-PickerView框架中的WheelView(滚轮视图)控件正是为解决这些问题而生。本文将从基础到进阶,全面解析WheelView的核心功能、使用方法和高级定制技巧,帮助开发者快速掌握这一强大控件。

读完本文后,你将能够:

  • 理解WheelView的核心架构与工作原理
  • 实现基础的单列/多列选择器
  • 定制滚轮的外观样式与交互行为
  • 解决数据联动与性能优化问题
  • 掌握常见场景的最佳实践方案

WheelView核心架构解析

类结构设计

WheelView采用模块化设计,主要由以下核心组件构成:

mermaid

核心属性与方法

WheelView提供了丰富的配置选项,通过xml属性或Java代码可进行灵活定制:

属性类别关键属性描述默认值
外观配置textSize文字大小16sp
textColorOut非选中项文字颜色#a8a8a8
textColorCenter选中项文字颜色#2a2a2a
dividerColor分割线颜色#d5d5d5
行为控制isLoop是否循环滚动true
lineSpacingMultiplier行间距倍数1.6f
itemsVisible可见条目数量11
交互设置onItemSelectedListener选中事件监听器null
gravity文字对齐方式CENTER

快速上手:基础使用步骤

1. 准备数据源

WheelView支持两种数据提供方式:基础数据类型和自定义实体类。

方式一:基础数据类型

// 字符串列表
List<String> dataList = new ArrayList<>();
dataList.add("北京");
dataList.add("上海");
dataList.add("广州");
dataList.add("深圳");

// 数组适配器
WheelAdapter adapter = new ArrayWheelAdapter(dataList);

方式二:自定义实体类(推荐)

// 实现IPickerViewData接口
public class ProvinceBean implements IPickerViewData {
    private String name;
    private String code;
    
    @Override
    public String getPickerViewText() {
        return name; // 用于滚轮显示的文本
    }
    
    // getter/setter省略
}

// 创建实体类列表
List<ProvinceBean> provinceList = new ArrayList<>();
provinceList.add(new ProvinceBean("北京", "110000"));
provinceList.add(new ProvinceBean("上海", "310000"));

2. 布局文件配置

在XML布局中添加WheelView控件:

<com.contrarywind.view.WheelView
    android:id="@+id/wheelView"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    app:wheelview_textSize="16sp"
    app:wheelview_textColorCenter="#FF4081"
    app:wheelview_dividerColor="#E0E0E0"
    app:wheelview_lineSpacingMultiplier="1.8"
    app:wheelview_gravity="center"/>

3. 基本初始化代码

在Activity或Fragment中初始化WheelView:

// 获取控件实例
WheelView wheelView = findViewById(R.id.wheelView);

// 设置适配器
wheelView.setAdapter(new ArrayWheelAdapter(provinceList));

// 设置初始选中项
wheelView.setCurrentItem(0);

// 设置循环滚动
wheelView.setCyclic(true);

// 设置选中监听器
wheelView.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(int index) {
        // 处理选中事件
        String selectedText = provinceList.get(index).getPickerViewText();
        Toast.makeText(context, "选中: " + selectedText, Toast.LENGTH_SHORT).show();
    }
});

高级定制:外观与交互优化

滚轮样式定制

WheelView提供了丰富的样式定制选项,满足不同UI需求:

// 设置文字大小
wheelView.setTextSize(18);

// 设置字体
wheelView.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/Roboto-Medium.ttf"));

// 设置分割线样式
wheelView.setDividerType(WheelView.DividerType.WRAP); // 包裹内容的分割线
wheelView.setDividerColor(Color.parseColor("#FF5722"));
wheelView.setDividerWidth(2);

// 设置透明度渐变
wheelView.setAlphaGradient(true);

// 设置文字偏移
wheelView.setTextXOffset(10);

交互行为定制

通过配置WheelView的交互参数,可以实现多样化的用户体验:

// 设置可见条目数量(建议设置奇数)
wheelView.setItemsVisibleCount(7);

// 禁用循环滚动
wheelView.setCyclic(false);

// 设置行间距倍数
wheelView.setLineSpacingMultiplier(2.0f);

// 设置选中项颜色
wheelView.setTextColorCenter(Color.parseColor("#FF4081"));

// 设置非选中项颜色
wheelView.setTextColorOut(Color.parseColor("#9E9E9E"));

自定义布局实现

对于复杂的UI需求,可以通过自定义布局实现完全个性化的滚轮样式:

// 创建自定义布局的OptionsPickerView
OptionsPickerView pvCustomOptions = new OptionsPickerBuilder(this, new OnOptionsSelectListener() {
    @Override
    public void onOptionsSelect(int options1, int options2, int options3, View v) {
        // 处理选中事件
    }
})
.setLayoutRes(R.layout.pickerview_custom_options, new CustomListener() {
    @Override
    public void customLayout(View v) {
        // 自定义布局初始化
        TextView tvSubmit = v.findViewById(R.id.tv_finish);
        ImageView ivCancel = v.findViewById(R.id.iv_cancel);
        
        tvSubmit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pvCustomOptions.returnData();
                pvCustomOptions.dismiss();
            }
        });
        
        ivCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pvCustomOptions.dismiss();
            }
        });
    }
})
.build();

// 设置数据
pvCustomOptions.setPicker(dataList);

多列联动实现方案

二级联动示例

以"省市联动"为例,实现二级数据联动:

// 初始化数据
List<ProvinceBean> provinceList = new ArrayList<>();
List<List<String>> cityList = new ArrayList<>();

// 添加省份数据
provinceList.add(new ProvinceBean("广东", "440000"));
provinceList.add(new ProvinceBean("广西", "450000"));

// 添加城市数据
List<String> guangdongCities = new ArrayList<>();
guangdongCities.add("广州");
guangdongCities.add("深圳");
guangdongCities.add("珠海");
cityList.add(guangdongCities);

List<String> guangxiCities = new ArrayList<>();
guangxiCities.add("南宁");
guangxiCities.add("柳州");
guangxiCities.add("桂林");
cityList.add(guangxiCities);

// 创建联动选择器
OptionsPickerView pvOptions = new OptionsPickerBuilder(this, new OnOptionsSelectListener() {
    @Override
    public void onOptionsSelect(int options1, int options2, int options3, View v) {
        String selectedProvince = provinceList.get(options1).getPickerViewText();
        String selectedCity = cityList.get(options1).get(options2);
        String result = selectedProvince + " " + selectedCity;
        // 更新UI显示
    }
})
.setPicker(provinceList, cityList) // 设置两级数据
.build();

// 显示选择器
pvOptions.show();

三级联动实现

对于省市区三级联动,实现方式类似但需要更复杂的数据结构:

// 三级数据结构示例
List<ProvinceBean> options1Items = new ArrayList<>();
List<ArrayList<CityBean>> options2Items = new ArrayList<>();
List<ArrayList<ArrayList<DistrictBean>>> options3Items = new ArrayList<>();

// 初始化数据...

// 创建三级联动选择器
OptionsPickerView pvOptions = new OptionsPickerBuilder(this, new OnOptionsSelectListener() {
    @Override
    public void onOptionsSelect(int options1, int options2, int options3, View v) {
        String tx = options1Items.get(options1).getPickerViewText() + 
                   options2Items.get(options1).get(options2).getPickerViewText() +
                   options3Items.get(options1).get(options2).get(options3).getPickerViewText();
        // 处理结果
    }
})
.setPicker(options1Items, options2Items, options3Items) // 设置三级数据
.build();

性能优化策略

数据加载优化

对于大量数据场景,采用分批加载和复用机制:

// 优化的ArrayWheelAdapter实现
public class OptimizedArrayWheelAdapter<T> implements WheelAdapter<T> {
    private List<T> mData;
    
    // 只在首次获取时计算,缓存结果
    private int[] mItemWidths;
    
    @Override
    public T getItem(int index) {
        // 处理循环逻辑
        if (mData == null || mData.isEmpty()) return null;
        return mData.get((index % mData.size() + mData.size()) % mData.size());
    }
    
    @Override
    public int getItemsCount() {
        return mData == null ? 0 : mData.size();
    }
    
    // 其他优化实现...
}

绘制性能优化

WheelView内部已实现多项绘制优化,但仍可通过以下方式进一步提升性能:

// 1. 减少不必要的重绘
wheelView.setWillNotDraw(false);

// 2. 使用硬件加速
wheelView.setLayerType(View.LAYER_TYPE_HARDWARE, null);

// 3. 避免在onDraw中创建对象
// 错误示例:在onDraw中new Paint()
// 正确做法:在构造函数中初始化并复用对象

内存管理

在Activity/Fragment生命周期中正确管理WheelView资源:

@Override
protected void onDestroy() {
    super.onDestroy();
    // 释放资源
    if (wheelView != null) {
        wheelView.cancelFuture(); // 取消异步任务
        wheelView.setOnItemSelectedListener(null); // 移除监听器
    }
}

常见问题解决方案

数据联动不同步

问题描述:选择第一级后,第二级数据未及时更新或显示异常。

解决方案:确保联动数据结构正确,并在选择监听器中手动更新下一级数据:

wheelView1.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(int index) {
        // 更新第二级数据
        List<String> secondLevelData = getSecondLevelData(index);
        wheelView2.setAdapter(new ArrayWheelAdapter(secondLevelData));
        wheelView2.setCurrentItem(0); // 重置选中项
    }
});

滚动卡顿问题

问题描述:数据量大时,滚轮滚动不流畅或出现掉帧。

解决方案

  1. 减少可见条目数量(建议5-7条)
  2. 优化数据适配器,避免在getItem中执行耗时操作
  3. 使用轻量级数据模型,减少对象创建开销
  4. 禁用透明度渐变(isAlphaGradient=false)
// 优化配置
wheelView.setItemsVisibleCount(5);
wheelView.setAlphaGradient(false);
wheelView.setAdapter(new OptimizedWheelAdapter(largeDataList));

初始位置设置无效

问题描述:调用setCurrentItem后,滚轮未正确定位到指定位置。

解决方案:确保在设置适配器后再设置初始位置,并调用invalidate():

// 正确顺序
wheelView.setAdapter(adapter);
wheelView.setCurrentItem(3);
wheelView.invalidate(); // 强制重绘

// 错误顺序(会导致设置无效)
wheelView.setCurrentItem(3); 
wheelView.setAdapter(adapter);

自定义布局不显示

问题描述:自定义布局后,滚轮或选择器不显示或显示异常。

解决方案:确保自定义布局包含必要的容器ID:

<!-- 自定义布局必须包含以下ID之一 -->
<LinearLayout
    android:id="@+id/optionspicker"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"/>
    
<!-- 或用于时间选择器 -->
<LinearLayout
    android:id="@+id/timepicker"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"/>

最佳实践案例

1. 时间选择器

利用WheelView实现自定义时间选择器:

private void initTimePicker() {
    Calendar selectedDate = Calendar.getInstance();
    Calendar startDate = Calendar.getInstance();
    startDate.set(2000, 0, 1);
    Calendar endDate = Calendar.getInstance();
    endDate.set(2030, 11, 31);
    
    pvTime = new TimePickerBuilder(this, new OnTimeSelectListener() {
        @Override
        public void onTimeSelect(Date date, View v) {
            // 处理选中时间
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(date);
        }
    })
    .setType(new boolean[]{true, true, true, true, true, false}) // 年月日时分秒
    .setLabel("年", "月", "日", "时", "分", "")
    .isCenterLabel(false)
    .setDividerColor(Color.parseColor("#E0E0E0"))
    .setContentTextSize(18)
    .build();
}

2. 省市区三级联动

实现完整的地址选择功能:

private void initAddressPicker() {
    // 从JSON文件加载数据
    String jsonData = new GetJsonDataUtil().getJson(this, "province.json");
    List<JsonBean> jsonBean = parseData(jsonData);
    
    // 初始化三级联动数据
    options1Items = jsonBean;
    options2Items = new ArrayList<>();
    options3Items = new ArrayList<>();
    
    for (int i = 0; i < jsonBean.size(); i++) {
        // 省
        options2Items.add(jsonBean.get(i).getCityList());
        
        List<ArrayList<String>> cityOptions = new ArrayList<>();
        for (int j = 0; j < jsonBean.get(i).getCityList().size(); j++) {
            // 市
            cityOptions.add(jsonBean.get(i).getCityList().get(j).getArea());
        }
        options3Items.add(cityOptions);
    }
    
    // 创建选择器
    pvOptions = new OptionsPickerBuilder(this, new OnOptionsSelectListener() {
        @Override
        public void onOptionsSelect(int options1, int options2, int options3, View v) {
            String address = options1Items.get(options1).getName() + 
                           options2Items.get(options1).get(options2).getName() +
                           options3Items.get(options1).get(options2).get(options3);
        }
    })
    .setPicker(options1Items, options2Items, options3Items)
    .build();
}

3. 商品规格选择器

实现电商场景中的多规格选择功能:

// 初始化规格数据
List<String> sizeList = Arrays.asList("S", "M", "L", "XL");
List<String> colorList = Arrays.asList("红色", "蓝色", "黑色", "白色");
List<String> versionList = Arrays.asList("标准版", "豪华版", "旗舰版");

// 创建不联动选择器
OptionsPickerView pvNoLinkOptions = new OptionsPickerBuilder(this, new OnOptionsSelectListener() {
    @Override
    public void onOptionsSelect(int options1, int options2, int options3, View v) {
        String spec = "尺寸:" + sizeList.get(options1) + 
                     " 颜色:" + colorList.get(options2) +
                     " 版本:" + versionList.get(options3);
        // 更新UI显示选中规格
    }
})
.setNPicker(sizeList, colorList, versionList) // 设置多列不联动数据
.setSelectOptions(0, 0, 0) // 设置默认选中项
.build();

// 显示选择器
pvNoLinkOptions.show();

总结与展望

WheelView作为Android-PickerView框架的核心组件,凭借其强大的功能、灵活的定制能力和优异的性能,成为解决Android选择器需求的理想选择。本文从基础使用到高级定制,全面介绍了WheelView的核心功能和最佳实践方案,涵盖了从简单选择器到复杂联动场景的实现方法。

随着移动应用交互体验要求的不断提高,WheelView也在持续进化。未来版本可能会引入更多高级特性,如:

  • 支持垂直/水平双向滚动
  • 增强的动画效果和过渡体验
  • 更丰富的手势操作支持
  • 与Jetpack Compose的深度集成

掌握WheelView的使用,将为你的Android应用带来更加专业和流畅的选择交互体验。无论是简单的下拉选择,还是复杂的多列联动,WheelView都能以最少的代码实现最优的效果,是每个Android开发者值得掌握的实用控件。

附录:完整代码示例

基础单列选择器完整代码

public class SingleColumnPickerActivity extends AppCompatActivity {
    private WheelView wheelView;
    private List<String> dataList = new ArrayList<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_single_column_picker);
        
        // 初始化数据
        initData();
        
        // 初始化WheelView
        initWheelView();
    }
    
    private void initData() {
        dataList.add("星期一");
        dataList.add("星期二");
        dataList.add("星期三");
        dataList.add("星期四");
        dataList.add("星期五");
        dataList.add("星期六");
        dataList.add("星期日");
    }
    
    private void initWheelView() {
        wheelView = findViewById(R.id.wheelView);
        
        // 设置适配器
        wheelView.setAdapter(new ArrayWheelAdapter(dataList));
        
        // 设置初始选中项
        wheelView.setCurrentItem(0);
        
        // 设置循环滚动
        wheelView.setCyclic(true);
        
        // 设置可见条目数量
        wheelView.setItemsVisibleCount(5);
        
        // 设置选中监听器
        wheelView.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(int index) {
                String selectedItem = dataList.get(index);
                Toast.makeText(SingleColumnPickerActivity.this, 
                               "选中: " + selectedItem, Toast.LENGTH_SHORT).show();
            }
        });
        
        // 自定义样式
        wheelView.setTextSize(18);
        wheelView.setTextColorCenter(Color.parseColor("#FF5722"));
        wheelView.setDividerColor(Color.parseColor("#EEEEEE"));
        wheelView.setLineSpacingMultiplier(1.6f);
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (wheelView != null) {
            wheelView.cancelFuture();
        }
    }
}

对应的布局文件:

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <com.contrarywind.view.WheelView
        android:id="@+id/wheelView"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        app:wheelview_gravity="center"
        app:wheelview_textSize="16sp"/>

</LinearLayout>

【免费下载链接】Android-PickerView This is a picker view for android , support linkage effect, timepicker and optionspicker.(时间选择器、省市区三级联动) 【免费下载链接】Android-PickerView 项目地址: https://gitcode.com/gh_mirrors/an/Android-PickerView

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值