mardi 18 mai 2021

How to build a custom list with checkboxes and result counter for every item?

I´m working on a project where I´m trying to implement a settings filter which alows a user to get individual results. The user should be able to choose different options to get individual results displayed in a paged recyclerview.

My first try

First I tried to achive that with different relativ layouts which included checkboxes and next to the checkboxes a textview which displays the size of the results for that single option. Cause my view gots to big I switched to a recyclerview as a list which should display some constant options for different categorys but with changing counters.

So I set up a recyclerview, a model class for the recyclerview adapter and an adapter. The order of the items should always be the same and also the text shouldn´t change at any time only the result size for the single options should change. Everything works beside of that fact that the order switch any time when I start a new session I got the result size for any option with a viewmodel and a web request.

My model class:

public class FilterItem implements Serializable {

public boolean state;
public String ItemName;
public Integer ItemCount;

public FilterItem (){}
public FilterItem(Boolean state,String ItemName,Integer ItemCount)
{
    this.state=state;
    this.ItemName=ItemName;
    this.ItemCount=ItemCount;
}

}

My Adapter:+ public class FilterListRecycler extends RecyclerView.Adapter<FilterListRecycler.FilterItemHolder> {

ArrayList<FilterItem> filterItem;
private final FilterItemInterface filterItemInterface;
Boolean isSelectedAll=true;

public FilterListRecycler(ArrayList<FilterItem> filterItem , FilterItemInterface filterItemInterface)
{
    this.filterItem=filterItem;
    this.filterItemInterface=filterItemInterface;
}
public void unselectall(){
    isSelectedAll=false;
    notifyDataSetChanged();
}

@Override
public @NotNull FilterItemHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    return new FilterItemHolder(FilterlistitemBinding.inflate(LayoutInflater.from(viewGroup.getContext())));
}

@SuppressLint("SetTextI18n")
@Override
public void onBindViewHolder(@NonNull FilterItemHolder holder, int position) {
    Log.d("TAG", "onBindViewHolder: "+position+" "+filterItem.get(position).state+" "+filterItem.get(position).ItemName+" "+filterItem.get(position).ItemCount);
    holder.filterlistitemBinding.checkbox.setChecked(filterItem.get(position).state);
    holder.filterlistitemBinding.checkbox.setText(filterItem.get(position).ItemName);
    holder.filterlistitemBinding.counter.setText("("+filterItem.get(position).ItemCount+")");
    if (!isSelectedAll) {
        holder.filterlistitemBinding.checkbox.setChecked(false);
        filterItem.get(position).state=false;
    }
    holder.filterlistitemBinding.checkbox.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            filterItemInterface.getFilterItem(filterItem.get(position));
        }
    });
}
@Override
public int getItemCount() {
    return filterItem.size();
}
public static class FilterItemHolder extends RecyclerView.ViewHolder {
    public FilterlistitemBinding filterlistitemBinding;

    public FilterItemHolder(FilterlistitemBinding filterlistitemBinding) {
        super(filterlistitemBinding.getRoot());
        this.filterlistitemBinding = filterlistitemBinding;
    }
}

}

Short version of my settings filter class:

public class Config_Filter extends DialogFragment implements FilterItemInterface {


FilterItem filterItem;
ArrayList<FilterItem> filterItems;
Bundle filterbundle;
FilterStates filterStates;
String adress;
MainViewModel viewModel;
LocationViewModel locationViewModel;
private final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
ArrayList<String> Genre,Art,Extra;
int radius=25, age, privat,StartPrice,EndPrice;
String starttime,endtime;
FilterListRecycler filterListRecycler;

double lat,lng;
public String Date;
public static final String TAG = "config_dialog";
FragmentConfigBinding binding;

@Override
public void onStart() {
    super.onStart();
    //dialog settings
    Dialog dialog = getDialog();
    if (dialog != null) {
        int width = ViewGroup.MarginLayoutParams.MATCH_PARENT;
        int height = ViewGroup.LayoutParams.MATCH_PARENT;
        dialog.getWindow().setLayout(width, height);
        ColorDrawable back = new ColorDrawable(Color.TRANSPARENT);
        InsetDrawable inset = new InsetDrawable(back, 0, 60, 0, 0);
        dialog.getWindow().setBackgroundDrawable(inset);
        dialog.getWindow().setWindowAnimations(R.style.AppTheme_Slide);
    }
}

@Override
public void onCreate(Bundle savedInstanceState) {
    setStyle(DialogFragment.STYLE_NO_FRAME, R.style.AppTheme_FullScreenDialog);
    super.onCreate(savedInstanceState);
    //current adress of user and lat and lng to get location oriented results
    lat=requireArguments().getDouble(Config.KEY_EMP_LAT);
    lng=requireArguments().getDouble(Config.KEY_EMP_LNG);
}
@SuppressLint({"SetTextI18n", "DefaultLocale"})
@Override
public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);
    binding = FragmentConfigBinding.inflate(inflater, container, false);
    //setup ArrayLists
    Genre=new ArrayList<>();
    Art=new ArrayList<>();
    Extra=new ArrayList<>();
    filterItems=new ArrayList<>();
    expandLayout();
    ViewModel();
    filtercount();
    recycler();
    RecyclerAdapter();

    return binding.getRoot();
}

public void filterartitems()
{
    filterItems.add(new FilterItem(false,getString(R.string.Bar),0));
    filterItems.add(new FilterItem(false,getString(R.string.Club),0));
    filterItems.add(new FilterItem(false,getString(R.string.Festival),0));
    filterItems.add(new FilterItem(false,getString(R.string.OpenAir),0));

}

public void ViewModel()
{
    viewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class);
    locationViewModel=new ViewModelProvider(requireActivity()).get(LocationViewModel.class);
}

public void recycler()
{
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
    linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    binding.expandart.setLayoutManager(new LinearLayoutManager(getContext()));

}

public boolean cleanParams()
{
    return Art.size() == 0 || Genre.size() == 0 || privat == 0 || age == 0 || radius == 25 || starttime.equals(getString(R.string.start)) || endtime.equals(getString(R.string.end)) || Date.equals(getString(R.string.Datum));
}
//count result size for the single options
@SuppressLint("SetTextI18n")
public void filtercount()
{
    viewModel.getFilteredData(lat,lng,firebaseAuth.getUid(),new ArrayList<String>(Collections.singletonList(getString(R.string.Bar))),Genre,Extra,privat,age,radius,starttime,endtime,StartPrice,EndPrice,Date).observe(getViewLifecycleOwner(), integer ->{
        if (filterItems.size() == 1) {
            filterItems.set(0, new FilterItem(filterItems.get(0).state, filterItems.get(0).ItemName, integer));
            filterListRecycler.notifyItemChanged(0);
        }
        filterItems.add(new FilterItem(false,getString(R.string.Bar),integer));
    });
    viewModel.getFilteredData(lat,lng,firebaseAuth.getUid(), new ArrayList<>(Collections.singletonList(getString(R.string.Club))),Genre,Extra,privat,age,radius,starttime,endtime,StartPrice,EndPrice,Date).observe(getViewLifecycleOwner(), integer ->{
        if (filterItems.size()==2) {
            filterItems.set(1, new FilterItem(filterItems.get(1).state, filterItems.get(1).ItemName, integer));
            filterListRecycler.notifyItemChanged(1);
        }
        filterItems.add(new FilterItem(false,getString(R.string.Club),integer));
    });
    viewModel.getFilteredData(lat,lng,firebaseAuth.getUid(), new ArrayList<>(Collections.singletonList(getString(R.string.Festival))),Genre,Extra,privat,age,radius,starttime,endtime,StartPrice,EndPrice,Date).observe(getViewLifecycleOwner(), integer -> {
        if (filterItems.size()==3) {
            filterItems.set(2, new FilterItem(filterItems.get(2).state, filterItems.get(2).ItemName, integer));
            filterListRecycler.notifyItemChanged(2);
        }
        filterItems.add(new FilterItem(false,getString(R.string.Festival),integer));
    });
    viewModel.getFilteredData(lat,lng,firebaseAuth.getUid(), new ArrayList<>(Collections.singletonList(getString(R.string.OpenAir))),Genre,Extra,privat,age,radius,starttime,endtime,StartPrice,EndPrice,Date).observe(getViewLifecycleOwner(), integer ->{
        if (filterItems.size()==4) {
            filterItems.set(3, new FilterItem(filterItems.get(3).state, filterItems.get(3).ItemName, integer));
            filterListRecycler.notifyItemChanged(3);
        }
        filterItems.add(new FilterItem(false,getString(R.string.OpenAir),integer));
    });
}

public void RecyclerAdapter()
{
    filterListRecycler=new FilterListRecycler(filterItems,this);
    binding.expandart.setAdapter(filterListRecycler);
}

public void expandLayout()
{
    binding.ArtConfig.setOnClickListener(v -> {
        if (binding.expandart.getVisibility()==View.GONE) {
            expand(binding.expandart);
            binding.ArtConfig.setActivated(true);
        }
        else {
            collapse(binding.expandart);
            binding.ArtConfig.setActivated(false);
        }
    });
}

@Override
public void getFilterItem(FilterItem filterItem) {
}
public static void expand(final View v) {
    int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
    int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    v.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
    final int targetHeight = v.getMeasuredHeight();
    // Older versions of android (pre API 21) cancel animations for views with a height of 0.
    v.getLayoutParams().height = 1;
    v.setVisibility(View.VISIBLE);
    Animation a = new Animation()
    {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            v.getLayoutParams().height = interpolatedTime == 1
                    ? LinearLayout.LayoutParams.WRAP_CONTENT
                    : (int)(targetHeight * interpolatedTime);
            v.requestLayout();
        }
        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };
    // Expansion speed of 1dp/ms
    a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
    v.startAnimation(a);
}
public static void collapse(final View v) {
    final int initialHeight = v.getMeasuredHeight();
    Animation a = new Animation()
    {
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            if(interpolatedTime == 1){
                v.setVisibility(View.GONE);
            }else{
                v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
                v.requestLayout();
            }
        }
        @Override
        public boolean willChangeBounds() {
            return true;
        }
    };
    // Collapse speed of 1dp/ms
    a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
    v.startAnimation(a);
}

}enter image description here




Aucun commentaire:

Enregistrer un commentaire