GridView Gallery | Images separated by header

I am creating an application with a gridView dialog. The whole gallery works well, but now I want to separate some photos from the other (need to create some headers). For example, I have some photos in my SD card folder named: 1v1.jpg / 1v2.jpg / 1v3.jpg / 2v1.jpg / 2v2.jpg, now I want to display it in my gridView gallery (let's suppose it has 2 columns)

How it should look like:

1

1v1.jpg 1v2.jpg

1v3.jpg

2

2v1.jpg 2v2.jpg

etc.

At the moment I only have a gallery with photos

Some codes:

GridAdapter:

public class GridAdapter extends BaseAdapter {

    Context mContext;
    ArrayList<File> listFiles;

    public GridAdapter(Context context, ArrayList<File> files) {

        this.mContext = context;
        this.listFiles = files;

    }

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

    @Override
    public Object getItem(int position) {
        return listFiles.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if(convertView == null)
        {
                convertView = LayoutInflater.from(mContext).inflate(R.layout.my_grid, parent, false);
        }

        final ImageView iv = (ImageView) convertView.findViewById(R.id.imageView);

       Glide.with(mContext)
                .load(listFiles.get(position).getAbsolutePath()) //path to picture
                .into(iv);


        return convertView;
    }

} //end of gridadapter

      

// rest code

public ArrayList<File> photoList;
public ArrayList<String> albumList;

photoList = imageReader(photoDir);
albumList = albumReader(photoDir);

//function to get all file paths (works)
    private ArrayList<File> imageReader(File root)
    {
        ArrayList<File> a = new ArrayList<>();
        File[] files = root.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {                 
                a.addAll(imageReader(file));
            } else {
                if (file.getName().length() == 14)
                {
                    a.add(file);
                }
            }
        }
        return a;
    }
        //function to get all headers name (works)
        private ArrayList<String> albumReader(File root)
        {
            ArrayList<String> pages = new ArrayList<>();
            File[] files = root.listFiles();
            for (File file : files)
            {
                String photoName;
                String temp = "";
                photoName =  file.getName();
                if(photoName.length()==14)
                {
                    photoName = photoName.substring(0, 4);        
                    if (!temp.equals(photoName))
                    {
                        if(pages.isEmpty() || !pages.contains(photoName))
                        {
                            pages.add(photoName);
                            temp = photoName;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

            }

            return pages;
        }

public void firstChoiceDialogGallery() {

        inflater = this.getLayoutInflater();

        // Dialog layout
        v = inflater.inflate(R.layout.dialog_choice, null);

        // Get gridView from dialog_choice
        gV = (GridView) v.findViewById(R.id.gridView);

        // GridAdapter (Pass context and files list)
        GridAdapter adapter = new GridAdapter(this, photoList);



        // Set adapter
        gV.setAdapter(adapter);

        final AlertDialog.Builder builder2 = new AlertDialog.Builder(this);
        builder2.setTitle("MY GALLERY");

        builder2.setView(v);
        builder2.setPositiveButton("NEXT", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        }).setNegativeButton("BACK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });

        builder2.setCancelable(false);
        final AlertDialog dialog = builder2.create();
        dialog.show();
    }

      

XML: grid_item.xml

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


    <ImageView
        android:layout_width="@integer/width"
        android:layout_height="@integer/height"
        android:adjustViewBounds="true"
        android:id="@+id/imageView"
        android:layout_margin="5dp"
        android:layout_centerVertical="true"
        android:layout_alignParentEnd="true" />

</RelativeLayout>

      

grid.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dialog_choice"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <GridView
        android:id="@+id/gridView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:numColumns="@integer/column_count"
        android:clickable="true"/>


</RelativeLayout>

      

As you can see, I wrote a function to get the names of the titles, the gallery works, but now I have no idea how to place these names in specific places and how to do it. I was thinking about putting it in my existing adapter, but it doesn't work.

PS I read about StickyGridHeaders so the link here to the lib source is unresponsive because I already know about it. The problem is I am not sure if this is what I want + I have no idea how to implement this existing code

+3


source to share


4 answers


You need to create a custom adapter named item_row.xml or whatever you want

item_row.xml

inside the layout specify the view you want, in your case you have an image view and a text view from what I can see:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="105dp"
android:layout_height="120dp">
<ImageView
    android:layout_width="70dp"
    android:layout_height="70dp"
    android:id="@+id/ImgItem"
    android:layout_marginTop="7dp"
    android:layout_gravity="center"/>
<TextView
    android:id="@+id/textItem"
    android:layout_width="120dp"
    android:layout_height="25dp"
    android:textSize="16sp"
    android:layout_marginBottom="3dp"
    android:layout_gravity="center"
    android:textColor="#182b4b"
    android:gravity="center" />
</LinearLayout>

      

now create your adapter class, here you will specify the adapter to inflate the newly created view (item_row, xml):

rowitem.java



make sure it continues from

ArrayAdapter

public class rowitem extends ArrayAdapter<String> {

private final Activity context;
private String[] nameItem;
private Bitmap[] iconsItem;

public rowitem(Activity context, String[] nameItem, Bitmap[] iconsItem) {
    super(context, R.layout.adapter_sketchmenuside, nameItem);
    // TODO Auto-generated constructor stub

    this.context = context;
    this.nameItem = nameItem;
    this.iconsItem = iconsItem;
}

public View getView(int posicion, View view, ViewGroup parent){
    LayoutInflater inflater = context.getLayoutInflater();
//inflate the item_row.xml view
    View rowView = inflater.inflate(R.item_row,null, 
true);

    TextView txtTitle = (TextView) rowView.findViewById(R.id.textItem);
    ImageView imageView = (ImageView) rowView.findViewById(R.id.ImgItem);

// Do your stuff
}

      

And as your last step, install a new custom adapter in the gridview where you declare it:

GridView myGrid = (GridView) view.findViewById(R.id.GrdCategory);

//in wherever you want, set the adapter:
myGrid.setAdapter(new rowitem(getActivity(), 
               namesArray, //here you send an Array with Strings for the names of the images
               imgArray, // here you send an array with the images you want to load
));

      

This will do, any questions let me know if correct, mark as correct. Happy coding!

+2


source


I assume you need to use a different View Type. Based on this, you can customize different layouts for headers and basic elements. This should be used for a document based RecyclerView with a StaggeredGridLayoutManager Layout Manager .



+1


source


A great way to achieve this behavior / layout. Try something like this:

sectionableAdapter:

public abstract class SectionableAdapter extends BaseAdapter {

public static final int MODE_VARY_WIDTHS = 0;
public static final int MODE_VARY_COUNT = 1;

private LayoutInflater inflater;
private int rowResID;
private int headerID;
private int itemHolderID;
private int colCount;
private int sectionsCount;
private int resizeMode;
private ViewGroup measuredRow;

public SectionableAdapter(LayoutInflater inflater, int rowLayoutID, int headerID, int itemHolderID)
{
    this(inflater, rowLayoutID, headerID, itemHolderID, MODE_VARY_WIDTHS);
}

/**
 * Constructor.
 * @param inflater inflater to create rows within the grid.
 * @param rowLayoutID layout resource ID for each row within the grid.
 * @param headerID resource ID for the header element contained within the grid row.
 * @param itemHolderID resource ID for the cell wrapper contained within the grid row. This View must only contain cells.
 */
public SectionableAdapter(LayoutInflater inflater, int rowLayoutID, int headerID, int itemHolderID, int resizeMode)
{
    super();
    this.inflater = inflater;
    this.rowResID = rowLayoutID;
    this.headerID = headerID;
    this.itemHolderID = itemHolderID;
    this.resizeMode = resizeMode;
    // Determine how many columns our row holds.
    View row = inflater.inflate(rowLayoutID, null);
    if (row == null)
        throw new IllegalArgumentException("Invalid row layout ID provided.");
    ViewGroup holder = (ViewGroup)row.findViewById(itemHolderID);
    if (holder == null)
        throw new IllegalArgumentException("Item holder ID was not found in the row.");
    if (holder.getChildCount() == 0)
        throw new IllegalArgumentException("Item holder does not contain any items.");
    colCount = holder.getChildCount();
    sectionsCount = getSectionsCount();
}

/**
 * Returns the total number of items to display.
 */
protected abstract int getDataCount();

/**
 * Returns the number of sections to display.
 */
protected abstract int getSectionsCount();

/**
 * @param index the 0-based index of the section to count.
 * @return the number of items in the requested section.
 */
protected abstract int getCountInSection(int index);

/**
 * @param position the 0-based index of the data element in the grid.
 * @return which section this item belongs to.
 */
protected abstract int getTypeFor(int position);

/**
 * @param section the 0-based index of the section.
 * @return the text to display for this section.
 */
protected abstract String getHeaderForSection(int section);

/**
 * Populate the View and attach any listeners.
 * @param cell the inflated cell View to populate.
 * @param position the 0-based index of the data element in the grid.
 */
protected abstract void bindView(View cell, int position);

/**
 * Perform any row-specific customization your grid requires. For example, you could add a header to the
 * first row or a footer to the last row.
 * @param row the 0-based index of the row to customize.
 * @param convertView the inflated row View.
 */
protected void customizeRow(int row, View rowView)
{
    // By default, does nothing. Override to perform custom actions.
}

@Override
public int getCount()
{
    int totalCount = 0;
    for (int i = 0; i < sectionsCount; ++i)
    {
        int count = getCountInSection(i);
        if (count > 0)
            totalCount += (getCountInSection(i)-1) / colCount + 1;
    }
    if (totalCount == 0)
        totalCount = 1;
    return totalCount;
}

@Override
public long getItemId(int position) {
    return 0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    int realPosition = 0;
    int viewsToDraw = 0;
    int rows = 0;
    int totalCount = 0;
    for (int i = 0; i < sectionsCount; ++i)
    {
        int sectionCount = getCountInSection(i);
        totalCount += sectionCount;
        if (sectionCount > 0 && position <= rows + (sectionCount - 1) / colCount)
        {
            realPosition += (position - rows) * colCount;
            viewsToDraw = (int)(totalCount - realPosition);
            break;
        }
        else
        {
            if (sectionCount > 0)
            {
                rows += (int)((sectionCount - 1) / colCount + 1);
            }
            realPosition += sectionCount;
        }
    }
    if (convertView == null)
    {
        convertView = inflater.inflate(rowResID, parent, false);
        if (measuredRow == null && resizeMode == MODE_VARY_COUNT)
        {
            measuredRow = (ViewGroup)convertView;
            // In this mode, we need to learn how wide our row will be, so we can calculate
            // the number of columns to show.
            // This listener will notify us once the layout pass is done and we have our
            // measurements.
            measuredRow.getViewTreeObserver().addOnGlobalLayoutListener(layoutObserver);
        }
    }
    int lastType = -1;
    if (realPosition > 0)
        lastType = getTypeFor(realPosition-1);
    if (getDataCount() > 0)
    {
        TextView header = (TextView)convertView.findViewById(headerID);
        int newType = getTypeFor(realPosition);
        if (newType != lastType)
        {
            header.setVisibility(View.VISIBLE);
            header.setText(getHeaderForSection(newType));

        }
        else
        {
            header.setVisibility(View.GONE);
        }
    }
    customizeRow(position, convertView);

    ViewGroup itemHolder = (ViewGroup)convertView.findViewById(itemHolderID);
    for (int i = 0; i < itemHolder.getChildCount(); ++i)
    {
        View child = itemHolder.getChildAt(i);
        if (i < colCount && i < viewsToDraw && child != null)
        {
            bindView(child, realPosition + i);
            child.setVisibility(View.VISIBLE);
        }
        else if (child != null)
        {
            child.setVisibility(View.INVISIBLE);
        }
    }
    return convertView;
}

private ViewTreeObserver.OnGlobalLayoutListener layoutObserver = new ViewTreeObserver.OnGlobalLayoutListener() {

    // The better-named method removeOnGlobalLayoutListener isn't available until a later API version.
    @SuppressWarnings("deprecation")
    @Override
    public void onGlobalLayout() {
        if (measuredRow != null)
        {
            int rowWidth = measuredRow.getWidth();
            ViewGroup childHolder = (ViewGroup)measuredRow.findViewById(itemHolderID);
            View child = childHolder.getChildAt(0);
            int itemWidth = child.getWidth();
            if (rowWidth > 0 && itemWidth > 0)
            {
                colCount = rowWidth / itemWidth;
                // Make sure this listener isn't called again after we layout for the next time.
                measuredRow.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                // The grid will now update with the correct column count.
                notifyDataSetChanged();
            }
        }
    }
};

}

      

BookcaseAdapter:

public class BookcaseAdapter extends SectionableAdapter implements
    View.OnClickListener {

// For simplicity, we hard-code the headers and data. In an actual app, this
// can come from the network, the filesystem, SQLite, or any of the 
// usual suspects.
static final String[] AUTHORS = new String[] { "Roberto Bola–o",
        "David Mitchell", "Haruki Murakami", "Thomas Pynchon" };
private static final String[][] BOOKS = new String[][] {
        { "The Savage Detectives", "2666" },
        { "Ghostwritten", "number9dream", "Cloud Atlas",
                "Black Swan Green", "The Thousand Autumns of Jacob de Zoet" },
        { "A Wild Sheep Chase",
                "Hard-Boiled Wonderland and the End of the World",
                "Norwegian Wood", "Dance Dance Dance",
                "South of the Border, West of the Sun",
                "The Wind-Up Bird Chronicle", "Sputnik Sweetheart",
                "Kafka on the Shore", "After Dark", "1Q84" },
        { "V.", "The Crying of Lot 49", "Gravity Rainbow", "Vineland",
                "Mason & Dixon", "Against the Day", "Inherent Vice" } };

private Activity activity;

public BookcaseAdapter(Activity activity, LayoutInflater inflater,
        int rowLayoutID, int headerID, int itemHolderID, int resizeMode) {
    super(inflater, rowLayoutID, headerID, itemHolderID, resizeMode);
    this.activity = activity;
}

@Override
public Object getItem(int position) {
    for (int i = 0; i < BOOKS.length; ++i) {
        if (position < BOOKS[i].length) {
            return BOOKS[i][position];
        }
        position -= BOOKS[i].length;
    }
    // This will never happen.
    return null;
}

@Override
protected int getDataCount() {
    int total = 0;
    for (int i = 0; i < BOOKS.length; ++i) {
        total += BOOKS[i].length;
    }
    return total;
}

@Override
protected int getSectionsCount() {
    return BOOKS.length;
}

@Override
protected int getCountInSection(int index) {
    return BOOKS[index].length;
}

@Override
protected int getTypeFor(int position) {
    int runningTotal = 0;
    int i = 0;
    for (i = 0; i < BOOKS.length; ++i) {
        int sectionCount = BOOKS[i].length;
        if (position < runningTotal + sectionCount)
            return i;
        runningTotal += sectionCount;
    }
    // This will never happen.
    return -1;
}

@Override
protected String getHeaderForSection(int section) {
    return AUTHORS[section];
}

@Override
protected void bindView(View convertView, int position) {
    String title = (String) getItem(position);
    TextView label = (TextView) convertView
            .findViewById(R.id.bookItem_title);
    label.setText(title);
    convertView.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    Intent i = new Intent(Intent.ACTION_SEARCH);
    TextView label = (TextView) v.findViewById(R.id.bookItem_title);
    String text = label.getText().toString();
    i.putExtra(SearchManager.QUERY, text);
    activity.startActivity(i);
}

}

      

SectionedGridActivity:

  public class SectionedGridActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sectioned_grid);

    ListView list = (ListView) findViewById(R.id.sectionedGrid_list);
    // Switch between these to see the two different types of resizing available.
    BookcaseAdapter adapter = new BookcaseAdapter(this,
            getLayoutInflater(), R.layout.book_row, R.id.bookRow_header,
            R.id.bookRow_itemHolder, SectionableAdapter.MODE_VARY_WIDTHS);
//      BookcaseAdapter adapter = new BookcaseAdapter(this,
//              getLayoutInflater(), R.layout.book_row_vary_columns, R.id.bookRow_header,
//              R.id.bookRow_itemHolder, SectionableAdapter.MODE_VARY_COUNT);
    list.setAdapter(adapter);
    list.setDividerHeight(0);
}

}

      

And all these layouts to work with it:

activity_sectioned_grid.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
 >

<ListView
    android:id="@+id/sectionedGrid_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:listSelector="@android:color/transparent"
    />

</RelativeLayout>

      

book_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="200dp"
android:layout_weight="1"
android:orientation="vertical" 
android:background="@drawable/gradients"
android:layout_margin="8dp"
>
<TextView
    android:id="@+id/bookItem_title"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:textColor="#ffffff"
    android:padding="8dp"
    />
</LinearLayout>

      

book_item_vary_columns.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="190dp"
android:layout_height="190dp"
android:orientation="vertical" 
android:padding="8dp"
>
<TextView
    android:id="@+id/bookItem_title"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:textColor="#ffffff"
    android:padding="8dp"
    android:background="@drawable/gradients"
    />
</LinearLayout>

      

book_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView 
    android:id="@+id/bookRow_header"
    style="@android:style/TextAppearance.Holo.Large"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="8dp"
    android:visibility="gone"
    />
<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:id="@+id/bookRow_itemHolder"
    >
    <include layout="@layout/book_item"/>
    <include layout="@layout/book_item"/>
</LinearLayout>

</LinearLayout>

      

book_row_vary_columns.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView 
    android:id="@+id/bookRow_header"
    style="@android:style/TextAppearance.Holo.Large"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="8dp"
    android:visibility="gone"
    />
<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:id="@+id/bookRow_itemHolder"
    >
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
    <include layout="@layout/book_item_vary_columns"/>
</LinearLayout>

</LinearLayout>

      

Please note that this code is not mine, it just fits the question and I researched this information before. Try google search for partitioned grid - you will find demo apk.

0


source


ok, for a layout like this you need basically different gridviews for different image sections, eg.

GridView 1 for 1v1.png 1v2.png etc.

GridView 2 for 2v1.png 2v2.png etc.

And these gridviews can be separated by the Textview header.

So, to implement this, you can make the parent layout as a Listview (instead of a gridview as you do).

And in that list, ItemRow can contain a Textview and a gridview below it.

This way the Listview will fill it in the exact layout you want. If you don't want any other library eg. as suggested above, then this can be done easily.

So the layouts will be:

parent layout:

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
    <ListView
        android:id="@+id/lv_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    </RelativeLayout>

      

And the element for this list will contain:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
    android:id="@+id/tv_header"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

<GridView
    android:id="@+id/gv_items"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:numColumns="2" />

      

and finally fill the gridview for images, the third layout will be:

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


<ImageView
    android:layout_width="@integer/width"
    android:layout_height="@integer/height"
    android:adjustViewBounds="true"
    android:id="@+id/imageView"
    android:layout_margin="5dp"
    android:layout_centerVertical="true"
    android:layout_alignParentEnd="true" />

</RelativeLayout>

      

0


source







All Articles