I have a listview with some items that can be marked as \"done\". There is also a togglebutton that says \"hide done items\".
However, when I do hide the items by s
After checking many solutions none of which was solved my issue with the empty space so I decided to came up with my solution.
I had two main issues: 1) I had an empty space because of the view that I set its visibility to gone 2) I had also dividerHeight of 12dp, even if I had the first issue solved I still had the fixed divider height of the listview
Solution:
1.1) I added a boolean to the data of the list, to notify the adapter which of the items are skipped
1.2) I created an empty layout to simulate an "skipped item"
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_height="0dp"/>
1.3) I have several types of views in my listview, selected item, regular item and now skipped item
public class AdvancedTestAdapter extends BaseAdapter
{
private static final int REGULAR_STEP = 0;
private static final int SELECTED_STEP = 1;
private static final int SKIPPED_STEP = 2;
private static final int TYPE_MAX_COUNT = 3;
private List<AdvancedTestData> _data;
private Context _context;
private Typeface _fontTypeFace;
public AdvancedTestAdapter(Context context, List<AdvancedTestData> data)
{
_context = context;
_data = data;
_fontTypeFace = Typeface.createFromAsset(_context.getResources().getAssets(), Consts.Fonts.UniversLTStdBoldCn);
}
@Override
public AdvancedTestData getItem(int position)
{
return _data.get(position);
}
@Override
public int getCount()
{
return _data.size();
}
@Override
public long getItemId(int position)
{
return 0;
}
@Override
public int getItemViewType(int position)
{
AdvancedTestData step = getItem(position);
if(step.isSkipped())
{
return SKIPPED_STEP;
}
return _data.get(position).isStepSelected() ? SELECTED_STEP : REGULAR_STEP;
}
@Override
public int getViewTypeCount()
{
return TYPE_MAX_COUNT;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
RegularViewHolder regHolder;
SelectedViewHolder selectHolder;
AdvancedTestData item = getItem(position);
int currentStepType = getItemViewType(position);
switch (currentStepType)
{
case SKIPPED_STEP:
convertView = LayoutInflater.from(_context).inflate(R.layout.skipped_item_layout, parent, false);
break;
case REGULAR_STEP:
if (convertView == null)
{
regHolder = new RegularViewHolder();
convertView = LayoutInflater.from(_context).inflate(R.layout.advanced_test_layout, parent, false);
regHolder._regTestUpperHeader = (TextView) convertView.findViewById(R.id.advanced_test_upper_name);
regHolder._regTestLowerHeader = (TextView) convertView.findViewById(R.id.advanced_test_lower_name);
regHolder._regTestImage = (ImageView) convertView.findViewById(R.id.advanced_test_image);
regHolder._regTestWithoutLowerHeader = (TextView) convertView.findViewById(R.id.step_without_lower_header);
regHolder._regTestUpperHeader.setTypeface(_fontTypeFace);
regHolder._regTestLowerHeader.setTypeface(_fontTypeFace);
regHolder._regTestWithoutLowerHeader.setTypeface(_fontTypeFace);
convertView.setTag(regHolder);
}
else
{
regHolder = (RegularViewHolder) convertView.getTag();
}
String upperHeader = item.getTestUpperHeader();
String lowerHeader = item.getTestLowerHeader();
if(lowerHeader.isEmpty())
{
regHolder._regTestUpperHeader.setVisibility(View.GONE);
regHolder._regTestLowerHeader.setVisibility(View.GONE);
regHolder._regTestWithoutLowerHeader.setVisibility(View.VISIBLE);
regHolder._regTestWithoutLowerHeader.setText(upperHeader);
}
else
{
regHolder._regTestUpperHeader.setVisibility(View.VISIBLE);
regHolder._regTestLowerHeader.setVisibility(View.VISIBLE);
regHolder._regTestWithoutLowerHeader.setVisibility(View.GONE);
regHolder._regTestUpperHeader.setText(upperHeader);
regHolder._regTestLowerHeader.setText(lowerHeader);
}
regHolder._regTestImage.setBackgroundResource(item.getResourceId());
break;
case SELECTED_STEP:
if (convertView == null)
{
selectHolder = new SelectedViewHolder();
convertView = LayoutInflater.from(_context).inflate(R.layout.advanced_selected_step_layout, parent, false);
selectHolder._selectedTestName = (TextView) convertView.findViewById(R.id.selected_header_text);
selectHolder._selectedTestDesc = (TextView) convertView.findViewById(R.id.selected_desc_text);
selectHolder._selectedPreFinishControllers = (RelativeLayout) convertView.findViewById(R.id.prefinish_step_controllers);
selectHolder._selectedFvEndControllers = (RelativeLayout) convertView.findViewById(R.id.advanced_fv_controllers);
selectHolder._selectedNvEndControllers = (RelativeLayout) convertView.findViewById(R.id.advanced_nv_controllers);
convertView.setTag(selectHolder);
}
else
{
selectHolder = (SelectedViewHolder) convertView.getTag();
}
selectHolder._selectedPreFinishControllers.setVisibility(View.INVISIBLE);
selectHolder._selectedFvEndControllers.setVisibility(View.INVISIBLE);
selectHolder._selectedNvEndControllers.setVisibility(View.INVISIBLE);
int testIndex = item.getTestIndex();
ADVANCED_QUICK_TEST_TESPS currentStep = ADVANCED_QUICK_TEST_TESPS.valueOf(testIndex);
//show action buttons in each step in advanced mode
switch (currentStep)
{
case QUESTIONS://nothing to show
break;
case RIGHT_VERIFICATION:
case LEFT_VERIFICATION:
case BINOCULAR_BALANCE:
case SPHERE_VERIFICATION:
case ADD_VERIFICATION:
if(item.isStepPreFinished())
{
selectHolder._selectedPreFinishControllers.setVisibility(View.VISIBLE);
}
break;
case RIGHT_VA:
case LEFT_VA:
case BINO_VA:
selectHolder._selectedPreFinishControllers.setVisibility(View.VISIBLE);
break;
case FV_DONE:
selectHolder._selectedFvEndControllers.setVisibility(View.VISIBLE);
break;
case FULL_EXAM_DONE:
selectHolder._selectedNvEndControllers.setVisibility(View.VISIBLE);
break;
}
String textHeader = String.format("%s\n%s", item.getTestUpperHeader(),item.getTestLowerHeader());
selectHolder._selectedTestName.setText(textHeader);
selectHolder._selectedTestDesc.setText(item.getTestDescription());
break;
}
return convertView;
}
public void setData(List<AdvancedTestData> data)
{
_data = data;
notifyDataSetChanged();
}
public static class RegularViewHolder
{
public TextView _regTestWithoutLowerHeader;
public TextView _regTestUpperHeader;
public TextView _regTestLowerHeader;
public ImageView _regTestImage;
}
public static class SelectedViewHolder
{
public TextView _selectedTestName;
public TextView _selectedTestDesc;
public RelativeLayout _selectedPreFinishControllers;
public RelativeLayout _selectedFvEndControllers;
public RelativeLayout _selectedNvEndControllers;
}
only if the item is skipped the adapter inflate to an empty layout as shown on previous step, still I had the divider height issue
2) To fix divider height I changed the divider height to 0 instead of 12dp, each item that is not skipped I added another layout with transparent background (the divier color in my case should be transparent) and added bottom padding of 12dp
for example one of my items
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:orientation="vertical"
android:paddingBottom="12dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/quick_test_background_selector" >
<ImageView
android:id="@+id/advanced_test_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/done_step" />
<TextView
android:id="@+id/advanced_test_upper_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@id/advanced_test_image"
android:gravity="center_vertical"
android:text="ETAPE 1"
android:textColor="@android:color/black"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/advanced_test_lower_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/advanced_test_image"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@id/advanced_test_image"
android:gravity="center_vertical"
android:text="ETAPE 1"
android:textColor="@android:color/black"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="@+id/step_without_lower_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/advanced_test_image"
android:layout_alignTop="@id/advanced_test_image"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@id/advanced_test_image"
android:gravity="center_vertical"
android:text="123"
android:textColor="@android:color/black"
android:textSize="14sp"
android:textStyle="bold" />
</RelativeLayout>
</RelativeLayout>
maybe its not elegant but this solution worked for me
View.GONE is actually releasing space but the other elements might have been confined to their current positions. Try this. In the custom layout file (which acts as view for the list items),
Suppose if X is the UI element you want to be GONE, W is the element below X and Y is the element above X
In the custom Layout of your ListView, (Assuming it's a relative layout) Attach the top of W to the bottom of X. And then attach the top of the element X to the bottom of Y.
Are you trying to hide the whole list item? If so I guess that the list view won't like that because it is still calculating with the same amount of items. I don't think it will just ignore it because it's gone.
The clean solution would be to return another getCount
and just ignore the items you want to hide. Or remove items from the internal used list. Call notifyDataSetChanged
on the adapter when you modified the amount of items in the list.
I was able to solve this problem using Knickedi's solution and the comments under it. Just wanted to show my relatively complete adapter to clarify it a bit.
I have the class StockItem with fields to hold a range of data for a single stock item. For the custom ArrayAdapter, the constructor takes the complete list of StockItems retrieved from a database table, and any add/remove methods I may add in the future will also operate on this list (mList). However, I overrode getView(), and getCount() to read from a second list (mFilteredList) produced using the method filterList():
public class StockItemAdapter extends ArrayAdapter<StockItem> {
...
ArrayList<StockItem> mList;
ArrayList<StockItem> mFilteredList;
public StockItemAdapter(Context context, int resource, ArrayList<StockItem> list) {
super(context, resource, list);
...
mList = list;
mFilteredList = list;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
StockItemHolder holder = null;
if (row == null) {
LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
row = inflater.inflate(mResource, parent, false);
holder = new StockItemHolder();
holder.imageView = (ImageView)row.findViewById(R.id.imageView);
...
row.setTag(holder);
} else {
holder = (StockItemHolder)row.getTag();
}
StockItem stockItem = mFilteredList.get(position);
if (stockItem.getImage() != null) {
holder.imageView.setImageBitmap(stockItem.getImage());
} else {
holder.imageView.setImageResource(R.drawable.terencephilip);
}
...
return row;
}
@Override
public int getCount() {
return mFilteredList.size();
}
static class StockItemHolder {
ImageView imageView;
...
}
public void filterList(String search) {
mFilteredList = new ArrayList<StockItem>();
for (StockItem item : mList) {
if (item.getDescription().toLowerCase(Locale.ENGLISH)
.contains(search.toLowerCase(Locale.ENGLISH))) {
mFilteredList.add(item);
}
}
notifyDataSetChanged();
}
}
filterList(String search) is called from an OnQueryTextListener and removes list items whose descriptions don't match the entered text.
In the case of a large list, filterList() may be a problem on the main thread, but that is irrelevant for this question.
EDIT: The getItem(position) method must also be overridden to return the item from mFilteredList.
@Override
public StockItem getItem(int position) {
return mFilteredList.get(position);
}
convertView = inflater.inflate(R.layout.custom_layout, parent, false);
if (CONDITION) {
holder.wholeLayout.getLayoutParams().height = 1; // visibility Gone not working && 0 height crash app.
} else {
holder.wholeLayout.getLayoutParams().height = RelativeLayout.LayoutParams.WRAP_CONTENT;
}
you should operate on the list adapter also...