Android可筛选的弹窗控件CustomFiltControl
作者:我守一座空城丶 发布时间:2023-01-21 09:01:46
本文实例为大家分享了Android弹窗控件CustomFiltControl的使用方法,供大家参考,具体内容如下
效果:
起初踩的坑:
刚开始是因为项目中需要用到筛选的功能,以前也遇到过但都是其他同事做的,而我看他们的实现大多都是自己一个个的码布局,然后做事件处理很麻烦,还有的是通过网上的一些线性排列控件自己组合实现的。
如今自己遇到了我开始想的也是通过LinearLayout动态去添加选项,title部分就是也是动态添加,一个打的LinearLayout包两个小的,然后在小的里面又包很多选项,但是遇到要换行的时候又需要添加一个LinearLayout,也就是但是有个问题,布局繁琐,得不到很好的复用。
后面突然想到了GridLayout,然后又使用了LinearLayout+GridLayout,对GridLayout是可以避免在你换行的时候去计算,只要你设置好行列,它会自动换行,这是确实实现了上面的效果,但是博主写好了又发现不够完美,既然GridLayout能自动换行,又可以一个站多行多列,为什么不把title也放到GridLayout中呢,有了这个想法,又来修改,在计算行列的时候确实遇到了阻碍,不过终究是完成了,最后封装在了popuwindow中直接调用。
看看主要实现吧:
package com.zzq.mack.customfiltcontrol;
import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.GridLayout;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;
import com.zzq.mack.customfiltcontrol.model.FiltModel;
import java.util.List;
/**
* Author:xqt
* Email:zzq1573@gmail.com
* Date:2018/3/31 0031 11:24
* Description:筛选弹框 版权所有转载请注明出处
*/
public class FiltPopuWindow extends PopupWindow{
public FiltPopuWindow(Context context,View view){
//这里可以修改popupwindow的宽高
super(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
setContentView(view);
initViews();
}
private void initViews() {
setAnimationStyle(R.style.popwin_anim_style);
//setBackgroundDrawable(new ColorDrawable(0x00000000));
setFocusable(true);
setOutsideTouchable(true);
}
public static class Builder {
private Context context;
private List<FiltModel> listData;
private int columnCount;
private GridLayout rootGridLayout;
private LinearLayout contextll;
//背景颜色
private int colorBg = Color.parseColor("#F8F8F8");
private int titleTextSize = 14;//SP
private int tabTextSize = 14;//SP
private int titleTextColor = Color.parseColor("#333333");//标题字体颜色
private int tabTextColor = R.color.fit_item_textcolor;//选项字体颜色
private int tabBgDrawable = R.drawable.item_lable_bg_shape;//选项背景颜色
//当前加载的行数
private int row = -1;
private FiltPopuWindow mFiltPopuWindow;
public Builder(Context context) {
this.context = context;
}
/**
* 设置数据源
* @return
*/
public Builder setDataSource(List<FiltModel> listData) {
this.listData = listData;
return this;
}
public Builder setColumnCount(int columnCount){
this.columnCount = columnCount;
return this;
}
public Builder setColorBg(int color){
colorBg = context.getResources().getColor(color);
return this;
}
public Builder setTitleTextSize(int titleTextSize) {
this.titleTextSize = titleTextSize;
return this;
}
public Builder setTabTextSize(int tabTextSize) {
this.tabTextSize = tabTextSize;
return this;
}
public Builder setTitleTextColor(int titleTextColor) {
this.titleTextColor = titleTextColor;
return this;
}
public Builder setTabTextColor(int tabTextColor) {
this.tabTextColor = tabTextColor;
return this;
}
public Builder setTabBgDrawable(int tabBgDrawable) {
this.tabBgDrawable = tabBgDrawable;
return this;
}
public Builder build(){
newItemLayout(getRowCount(),columnCount);
for (int i = 0; i < listData.size(); i++){
++row;
TextView view = new TextView(context);
view.setText(listData.get(i).getTypeName());
view.setTextColor(titleTextColor);
view.setTextSize(titleTextSize);
//配置列 第一个参数是起始列标 第二个参数是占几列 title(筛选类型)应该占满整行,so -> 总列数
GridLayout.Spec columnSpec = GridLayout.spec(0,columnCount);
//配置行 第一个参数是起始行标 起始行+起始列就是一个确定的位置
GridLayout.Spec rowSpec = GridLayout.spec(row);
//将Spec传入GridLayout.LayoutParams并设置宽高为0或者WRAP_CONTENT,必须设置宽高,否则视图异常
GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowSpec, columnSpec);
lp.width = GridLayout.LayoutParams.WRAP_CONTENT;
lp.height = GridLayout.LayoutParams.WRAP_CONTENT;
lp.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
lp.bottomMargin = context.getResources().getDimensionPixelSize(R.dimen.dp_8);
rootGridLayout.addView(view,lp);
//添加选项
addTabs(listData.get(i),i);
}
return this;
}
private void newItemLayout(int rowCount,int columnCount){
contextll = new LinearLayout(context);
contextll.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
contextll.setBackgroundColor(context.getResources().getColor(R.color.color_33000000));
contextll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mFiltPopuWindow != null){
mFiltPopuWindow.dismiss();
//点击外部消失
}
}
});
rootGridLayout = new GridLayout(context);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
rootGridLayout.setOrientation(GridLayout.HORIZONTAL);
rootGridLayout.setRowCount(rowCount);
rootGridLayout.setColumnCount(columnCount);
rootGridLayout.setBackgroundColor(colorBg);
rootGridLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
int pandd = context.getResources().getDimensionPixelSize(R.dimen.dp_10);
lp.weight = 1;
rootGridLayout.setPadding(pandd,pandd,pandd,pandd);
contextll.addView(rootGridLayout,lp);
}
/**
* 添加选项
* @param model
*/
private void addTabs(final FiltModel model, final int titleIndex){
List<FiltModel.TableMode> tabs = model.getTabs();
for (int i = 0; i < tabs.size(); i++){
if (i % columnCount == 0){
row ++;
}
final FiltModel.TableMode tab = tabs.get(i);
final TextView lable = new TextView(context);
lable.setTextColor(context.getResources().getColorStateList(tabTextColor));
lable.setBackgroundDrawable(context.getResources().getDrawable(tabBgDrawable));
lable.setSingleLine(true);
lable.setGravity(Gravity.CENTER);
lable.setEllipsize(TextUtils.TruncateAt.MIDDLE);
//这里可以自行修改tab框框的大小
int panddT = context.getResources().getDimensionPixelSize(R.dimen.dp_2);
int panddL = context.getResources().getDimensionPixelSize(R.dimen.dp_8);
lable.setPadding(panddL,panddT,panddL,panddT);
lable.setTextSize(tabTextSize);
rootGridLayout.addView(lable,getItemLayoutParams(i,row));
lable.setText(tab.name);
if (tabs.get(i) == model.getTab()){
lable.setSelected(true);
}
lable.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//lable.setSelected(true);
if (tab != model.getTab()){
//清空上次选中
rootGridLayout.getChildAt(getIndex(model,titleIndex)).setSelected(false);
//设置当前选中
model.setTab(tab);
lable.setSelected(true);
}
}
});
}
}
private GridLayout.LayoutParams getItemLayoutParams(int i,int row){
//使用Spec定义子控件的位置和比重
GridLayout.Spec rowSpec = GridLayout.spec(row,1f);
GridLayout.Spec columnSpec = GridLayout.spec(i%columnCount,1f);
//将Spec传入GridLayout.LayoutParams并设置宽高为0,必须设置宽高,否则视图异常
GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowSpec, columnSpec);
lp.width = 0;
lp.height = GridLayout.LayoutParams.WRAP_CONTENT;
lp.bottomMargin = context.getResources().getDimensionPixelSize(R.dimen.dp_8);
if(i % columnCount == 0) {//最左边
lp.leftMargin = context.getResources().getDimensionPixelSize(R.dimen.dp_10);
lp.rightMargin = context.getResources().getDimensionPixelSize(R.dimen.dp_20);
}else if((i + 1) % columnCount == 0){//最右边
lp.rightMargin = context.getResources().getDimensionPixelSize(R.dimen.dp_10);
}else {//中间
lp.rightMargin = context.getResources().getDimensionPixelSize(R.dimen.dp_20);
}
return lp;
}
/**
* 获取当前选中tab的 在整个GridLayout的索引
* @return
*/
private int getIndex(FiltModel model,int titleIndex){
int index = 0;
for (int i = 0; i < titleIndex; i++){
//计算当前类型之前的元素所占的个数 title算一个
index += listData.get(i).getTabs().size() + 1;
}
//加上当前 title下的索引
FiltModel.TableMode tableModel = model.getTab();
index += model.getTabs().indexOf(tableModel) + 1;
return index;
}
/**
* 计算行数
* @return
*/
private int getRowCount(){
int row = 0;
for (FiltModel model : listData){
//计算当前类型之前的元素所占的个数 title算一个
row ++;
int size = model.getTabs().size();
row += (size / columnCount) + (size % columnCount > 0 ? 1 : 0) ;
}
return row;
}
public FiltPopuWindow createPop(){
if (listData == null || listData.size() == 0){
try {
throw new Exception("没有筛选条件");
} catch (Exception e) {
Toast.makeText(context,e.getMessage(),Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
return null;
}
mFiltPopuWindow = new FiltPopuWindow(context,contextll);
return mFiltPopuWindow;
}
}
}
通过设置columnCount的大小可以改变列数,测试2,3,4,5没问题,只是列数越多就越挤,这是必然的。
希望对你有帮助,有问题欢迎给我留言。
这里准备了一个demo作为参考
GitHub:CutomFiltControl
来源:https://blog.csdn.net/quan648997767/article/details/79817883
猜你喜欢
- 开发环境使用jdk1.8.0_60,把springboot 项目打成war包后,部署到apache-tomcat-7.0.68时报错如下,换
- 启动第二个服务时就会报如下的错误:Server failed to start for port 8080: Address already
- 业务场景近年来B2C、O2O等商业概念的提出和移动端的发展,使得分布式系统流行了起来。分布式系统相对于单系统,解决了流量大、系统高可用和高容
- 前言Java多线程实现方式主要有四种:① 继承Thread类、实现Runnable接口② 实现Callable接口通过FutureTask包
- 现在我们常见的一些关于Linux的系统很多,但是使用的更多的一般都是CentOS和Ubuntu,今天我就来记录一下关于centos下java
- 使用IDEA开发微服务项目,需要启动多个微服务,可以开启IDEA的Run DashBoard窗口,需要对IDEA中指定工程的父工程进行配置进
- 1、迭代器迭代器(iterator)解决的是集合访问的问题,提供一种方法顺序访问一个集合对象中的各个元素,而不暴露对象内部标识。迭代器还有一
- 使用的是 idea - Lifecycle-package 的方式打包(maven)确认 <packaging>wa
- @Autowired注解注入的xxxMapper报错项目场景Mybatis-Plus测试问题描述在Mybatis-Plus场景的测试中发现,
- 一、安装本地Maven选择你需要的maven版本下载:官网下载传送门我使用的是3.6.1版本:maven-3.6.1-bin.zip&nbs
- 引言坦白从宽吧,我就是那个花了两天两夜把 1M 图片优化到 100kb 的家伙——王小二!自从因为一
- 1 MyBatisPlusConfigMyBatisPlus配置类。package com.config;import
- 冒泡排序:就是按索引逐次比较相邻的两个元素,如果大于/小于(取决于需要升序排还是降序排),则置换,否则不做改变这样一轮下来,比较了n-1次,
- Wrapper---条件查询器:使用它可以实现很多复杂的查询1.条件查询1.1查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于1
- zuul动态路由网关服务是流量的唯一入口。不能随便停服务。所以动态路由就显得尤为必要。数据库动态路由基于事件刷新机制热修改zuul的路由属性
- 一、在java中遍历一个文件夹里边的所有文件,可以有两种方式:1.递归遍历,通常也是开发者第一时间能想到的方法,递归遍历的优点是:实现起来相
- 前言Java虽然五脏俱全但总有软肋,譬如获取CPU等硬件信息,当然我们可以通过JNI调用C/C++来获取,但对于对C/C++和Windows
- 目录1、通过session中的token验证步骤1:创建自定义注解步骤2:创建自定义 * (@slf4j是lombok的注解)步骤3:将自定
- 这篇文章主要介绍了springboot日期转换器实现实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 什么是流?流:程序和设备之间连接起来的一根用于数据传输的管道,流就是一根管道。流的分类:四大基本抽象流(输入流,输出流,字符流,字节流)文件