Search code examples
androidviewandroid-viewpager

Android - removing Object from pageView results in blank space


I'm about to program an app for controlling some LED-based gadgets around the house. To have multiply devices on one activity I used a page view with a view adapter to be able to select between the linked devices. Currently, I'm stuck with deleting views from the container. As soon as I delete the View, it disappears but leaves a blanc space inside my ViewPager as you can see in the picture below. I tried everything suggested by other users, like returning

POSITION_NONE

when overwriting the

getItemPosition

method. I provide you with the code of my pageViewAdapter. I hope someone can suggest a solution to that problem. I'm very stuck here.

package com.example.fabsinnenraumgestaltung;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.cardview.widget.CardView;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import java.util.ArrayList;
import java.util.List;

public class CardPagerAdapter extends PagerAdapter implements CardAdapter {

ViewPager viewPager;
MainActivity mainActivity;

private List<CardView> mViews;
private List<CardItem> mData;
private float mBaseElevation;

public CardPagerAdapter(MainActivity mainActivity, ViewPager viewPager) {
    mData = new ArrayList<>();
    mViews = new ArrayList<>();
    this.mainActivity = mainActivity;
    this.viewPager = viewPager;
}

public void addCardItem(CardItem item) {
    mViews.add(null);
    mData.add(item);
}

public float getBaseElevation() {
    return mBaseElevation;
}

@Override
public CardView getCardViewAt(int position) {
    return mViews.get(position);
}

@Override
public int getCount() {
    return mData.size();
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    mData.set(position, null);
    mViews.set(position, null);
    notifyDataSetChanged();

}

@Override
public void notifyDataSetChanged() {
    super.notifyDataSetChanged();
}

@Override
public int getItemPosition(@NonNull Object object) {
    return super.getItemPosition(object);
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Button deleteButton;
    Button editButton;

    View view = LayoutInflater.from(container.getContext())
            .inflate(R.layout.device_card_layout, container, false);

    deleteButton = view.findViewById(R.id.deleteButton);
    editButton = view.findViewById(R.id.editButton);

    deleteButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            System.out.println("delete");
            deleteCardOperation(viewPager.getCurrentItem(), container);

        }
    });

    editButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            System.out.println("edit");
            int currentCard = viewPager.getCurrentItem();
        }
    });

    container.addView(view);
    bind(mData.get(position), view);
    CardView cardView = (CardView) view.findViewById(R.id.itemCard);

    if (mBaseElevation == 0) {
        mBaseElevation = cardView.getCardElevation();
    }



    cardView.setMaxCardElevation(mBaseElevation * MAX_ELEVATION_FACTOR);
    mViews.set(position, cardView);

    return view;
}





private void bind(CardItem item, View view) {
    TextView titleTextView = (TextView) view.findViewById(R.id.itemText);
    TextView ipTextView = (TextView) view.findViewById(R.id.itemIPAdress);
    TextView statusView = (TextView) view.findViewById(R.id.itemActiveStatus);
    titleTextView.setText(item.getName());
    ipTextView.setText(item.getIp());
    statusView.setText(item.getStatus());


}

private void deleteCardOperation(int cardIndicator, ViewGroup desV){


    CardItem x = mData.get(cardIndicator);

    AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity, android.R.style.Theme_Material_Dialog_Alert);
    builder.setTitle("Confirm");
    builder.setMessage("Are you sure you want to delete this device: "+ x.getName() + " ?");
    builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            destroyItem(desV, cardIndicator, getCardViewAt(cardIndicator));
            dialog.dismiss();
        }
    });

    builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // Do nothing
            dialog.dismiss();
        }
    });

    AlertDialog alert = builder.create();
    alert.show();

}

private void editCard(){

}




}

enter image description here

I really hope you can help. Thanks.

First edit:

I edited my code as Michiel suggested. I now call a deleteCardItem() method to remove the data from my dataset like shown below.

public void deleteCardItem(int position){
    mData.remove(position);
    notifyDataSetChanged();
}

With notifyDatasetChanged beeing called, the system takes over and calls getItemPosition(). Ive edited this method as well like Michiel suggested.

@Override
 public int getItemPosition(@NonNull Object object) {
    //return super.getItemPosition(object);

    int position = mData.indexOf(object);

    if(position == -1){
        return POSITION_NONE;
    }else{
        return position;
    }


}

Problem now is, that i can not compare the given "object" with any dataset, because "object" is a View object and mData is my Arraylist aka dataset. That leads to a starnge behaviour in my app. The card will not disapear anymore. It is shown but the data is deleted. I would appreciate further help.


Solution

  • To fully destroy the view itself you should try to write destroyItem like this:

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
            mViews.set(position, null);
    }
    

    So the View object is fully destroyed. And also try to set the View to null in deleteCardItem

    @Override
    public void deleteCardItem(int position){
            mData.remove(position);
            mViews.set(position, null);
            notifyDataSetChanged();
    }
    

    And also try to search for the View instead of the Data inside of getItemPosition.

    @Override
    public int getItemPosition(@NonNull Object object) {
            int position = mViews.indexOf(object);
            if(position == -1){
                    return POSITION_NONE;
            }else{
                    return position;
            }
    }
    

    After that, you don't see them anymore