Android: GridLayout size and View.GONE behaviour

谁都会走 提交于 2021-01-26 21:42:52

问题


I want to make a GridLayout that when one of it's children's Visibility is set to GONE, it is replaced by the next child.

This is no assignment I drew that myself to better explain.

I can get the layout working as in number of columns and width and all. Just the default GONE behaviour of GridLayout makes the child just disappear instead of being replaced as if it wasn't there in the first place, like other layouts work.

I did try a lot of stuff, I tried searching SO and google, but I can't seem to work this out. And this would be the most convenient layout for the app I'm working on.Is there anyway to do this in layout without having to do this programmatically?Or maybe a combination of both?


回答1:


The solution would be to use RecyclerView along with GridLayoutManager. The key is to notify adapter about the changes to deleted items by using notifyItemRemoved. There is lots of room for customization in RecyclerViews, such as nice animations for disappearing items, rearrangement of remaining items on the screen, item decorations and etc. You can apply all these customization and additional logic around deletion of the items as needed for your particular problem.

Activity

public class MainActivity extends AppCompatActivity {
    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        List<String> dataSet = getSampleDataSet();
        recyclerView = (RecyclerView) findViewById(R.id.grid);
        recyclerView.setAdapter(new MyAdapter(dataSet));
        recyclerView.setLayoutManager(new GridLayoutManager(getApplicationContext(), 2));
    }

    private List<String> getSampleDataSet() {
        List strings = new ArrayList();
        strings.add("one");
        strings.add("two");
        strings.add("three");
        strings.add("four");
        strings.add("five");
        strings.add("six");

        return strings;
    }
}

Adapter

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    List<String> dataSet;



    public MyAdapter(List<String> dataSet) {
        this.dataSet = dataSet;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        TextView tileView = (TextView) LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_item, parent, false);
        MyViewHolder myViewHolder = new MyViewHolder(tileView);

        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        holder.view.setText(dataSet.get(position));

        holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dataSet.remove(position);
                notifyItemRemoved(position); // this notifies the adapter about item being removed
            }
        });

    }

    @Override
    public int getItemCount() {
        return dataSet.size();
    }
}


class MyViewHolder extends RecyclerView.ViewHolder {
    TextView view;

    public MyViewHolder(TextView itemView) {
        super(itemView);
        view = itemView;
    }
}

Activity Layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/grid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

Grid Item

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridItem"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@color/colorPrimary"
    android:textColor="@android:color/white"
    android:gravity="center"
    android:text="Tile"/>

Results Before:

After click on 4. On an actual device, you will be able to see a nice framework animation for this action.




回答2:


Solve same problem as:

package ua.vsgroup.widgets;

import android.content.Context;
import android.support.v7.widget.GridLayout;
import android.util.AttributeSet;
import android.view.View;

public class vsGridLayout extends GridLayout {

    View[] mChild = null;

    public vsGridLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public vsGridLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public vsGridLayout(Context context) {
        this(context, null);
    }

    private void arrangeElements() {

        mChild = new View[getChildCount()];
        for (int i = 0; i < getChildCount(); i++) {
            mChild[i] = getChildAt(i);
        }

        removeAllViews();
        for (int i = 0; i < mChild.length; i++) {
            if (mChild[i].getVisibility() != GONE)
                addView(mChild[i]);
        }
        for (int i = 0; i < mChild.length; i++) {
            if (mChild[i].getVisibility() == GONE)
                addView(mChild[i]);
        }

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

        arrangeElements();
        super.onLayout(changed, left, top, right, bottom);

    }


}



回答3:


If you don't need turn the view visible again you can solve it removing the view from GridLayout.

private void hideView(View view) {
    GridLayout gridLayout = (GridLayout) view.getParent();
    for (int i = 0; i <  gridLayout.getChildCount(); i++) {
        if (view == gridLayout.getChildAt(i)) {
            gridLayout.removeViewAt(i);
            break;
        }
    }
}



回答4:


Based on this answer. Thanks man.

Create your custom GridLayout widget.

package com.isolpro.pricelist.custom;    

public class RearrangingGridLayout extends GridLayout {
  private final List<View> views = new ArrayList<>();

  public RearrangingGridLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  public RearrangingGridLayout(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public RearrangingGridLayout(Context context) {
    this(context, null);
  }

  private void arrangeElements() {
    removeAllViews();

    for (int i = 0; i < views.size(); i++) {
      if (views.get(i).getVisibility() != GONE)
        addView(views.get(i));
    }
  }

  public void saveViews() {
    for (int i = 0; i < getChildCount(); i++) {
      views.add(getChildAt(i));
    }
  }

  public void hideViewAtIndex(int index) {
    if (index >= 0 && index < views.size()) {
      views.get(index).setVisibility(GONE);
      arrangeElements();
    }
  }

  public void showViewAtIndex(int index) {
    if (index >= 0 && index < views.size()) {
      views.get(index).setVisibility(VISIBLE);
      arrangeElements();
    }
  }
}

Here is how to use it:

Save all the children of the GridLayout after it is bound (rendered), use the following code

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    RearrangingGridLayout rglPrices = findViewById(R.id.rglPrices);

    rglPrices.saveViews();
  }

Now, to hide your view

rglPrices.hideViewAtIndex(indexOfView);

Similarly, to show your view

rglPrices.showViewAtIndex(indexOfView);

And you are done!

For my project, it was essential to preserve the children's position so I went with index. You can easily modify the code to work with something else like view id, by updating the show and hide functions.



来源:https://stackoverflow.com/questions/33903001/android-gridlayout-size-and-view-gone-behaviour

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!