Reputation: 343
I have created a simple gallery that shows all the images on a phone. I would like to section off the images by date (month), and would also like a top section with the most recent photos taken. Please refer to the following image:
How can I go about doing this?
My Code:
SelectFileActivity.Java
public class SelectFileActivity extends AppCompatActivity {
RecyclerView recyclerView;
GalleryAdapter galleryAdapter;
List < String > images;
TextView gallery_number;
ImageView back_arrow;
private static final int REQUEST_CODE_STORAGE_PERMISSION = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_file);
// Remove status bar
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
// Initialize content
gallery_number = findViewById(R.id.gallery_number);
recyclerView = findViewById(R.id.recyclerview_gallery_images);
back_arrow = findViewById(R.id.select_file_back_arrow);
// Check for permission
if (ContextCompat.checkSelfPermission(SelectFileActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(SelectFileActivity.this,
new String[] {
Manifest.permission.READ_EXTERNAL_STORAGE
}, REQUEST_CODE_STORAGE_PERMISSION);
} else {
loadImages();
}
}
@Override
public void onBackPressed() {
startActivity(new Intent(this, HomeActivity.class));
finish();
}
private void loadImages() {
recyclerView.setHasFixedSize(true);
// Set the number of pictures per a row
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
images = SelectImagesGallery.listOfImages(this);
galleryAdapter = new GalleryAdapter(this, images, new GalleryAdapter.PhotoListener() {
@Override
public void onPhotoClick(String path) {
// Do something with the selected photo
}
});
recyclerView.setAdapter(galleryAdapter);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_STORAGE_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
loadImages();
} else {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
}
}
}
GalleryAdapter.java
public class GalleryAdapter extends RecyclerView.Adapter < GalleryAdapter.ViewHolder > {
private Context context;
private List < String > images;
protected PhotoListener photoListener;
public GalleryAdapter(Context context, List < String > images, PhotoListener photoListener) {
this.context = context;
this.images = images;
this.photoListener = photoListener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(
LayoutInflater.from(context).inflate(R.layout.gallery_item, parent, false)
);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
String image = images.get(position);
// Load images to Glide
Glide.with(context)
.load(image)
.transform(new CenterCrop(), new RoundedCorners(15))
.into(holder.image);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
photoListener.onPhotoClick(image);
}
});
}
@Override
public int getItemCount() {
return images.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView image;
public ViewHolder(@NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.image);
}
}
public interface PhotoListener {
void onPhotoClick(String path);
}
}
activity_select_file.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:background="@color/windowBackground"
android:orientation="vertical"
tools:context=".upload.SelectFileActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview_gallery_images"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Upvotes: 2
Views: 2598
Reputation: 415
Create two xmls and two viewholders for them. In your data list also add months as objects and in your onCreateViewHolder
method, check viewType and inflate proper xml for that.
I had to implement something similar in one of my projects and this was how my adapter looked like. It is just a sample application and of course these functionalities could be implemented far more better. You need to implement them as you want with a better design.
First you need to implement your own RecyclerView adapter:
public class RvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<GalleryBaseModel> _data;
Context context ;
public RvAdapter(Context context){
this.context = context;
this._data = new ArrayList<>();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == 1){ //DATE
return new DateViewHolder(
LayoutInflater.from(context).inflate(R.layout.date_layout, parent, false)
);
}
else { //Image
return new ImageViewHolder(
LayoutInflater.from(context).inflate(R.layout.image_layout, parent, false)
);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (getItemViewType(position) == 1){
// set date here
FlexboxLayoutManager.LayoutParams layoutParams = (FlexboxLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
layoutParams.setFlexGrow(1.0f);
layoutParams.width = MATCH_PARENT;
holder.itemView.setLayoutParams(layoutParams);
}
else {
// set image here
FlexboxLayoutManager.LayoutParams layoutParams = (FlexboxLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
layoutParams.setFlexGrow(1.0f);
layoutParams.width = getWidth();
holder.itemView.setLayoutParams(layoutParams);
}
}
/**
* A function to calculate width of your image cardViews.
* As it is a sample application I just return constant value, but you should calculate it.
* For example screenWidth/3
* @return Width of image cardView
*/
public int getWidth(){
return 200;
}
@Override
public int getItemCount() {
return _data.size();
}
@Override
public int getItemViewType(int position) {
return _data.get(position).getType();
}
class DateViewHolder extends RecyclerView.ViewHolder{
TextView dateTv;
public DateViewHolder(@NonNull View itemView) {
super(itemView);
dateTv = itemView.findViewById(R.id.dateTv);
}
}
class ImageViewHolder extends RecyclerView.ViewHolder{
ImageView mImage;
public ImageViewHolder(@NonNull View itemView) {
super(itemView);
mImage = itemView.findViewById(R.id.mImage);
}
}
public void addItem(GalleryBaseModel item){
this._data.add(item);
notifyDataSetChanged();
}
}
This is my image_view.xml
:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView android:layout_width="match_parent"
android:background="@android:color/black"
android:layout_height="120dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/mImage"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
And this is my date_layout.xml
:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/dateTv"
android:text="June 2020"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Here is my GalleryBaseModel.java
which is base model class for objects that need to be inflated in my adapter.
public abstract class GalleryBaseModel {
abstract int getType();
}
All classes inheriting this abstract class need to implement getType()
method and return the type of model they actually are.For example here 1 was for my date model and 0 was for my image model.Since these are pretty simple I don't include them in the answer.
And finally here is how I setup my recyclerView:
//this could be onCreate method of your activity or any other proper method in activity or fragment or ...
adapter = new RvAdapter(getApplicationContext());
flexboxLayoutManager = new FlexboxLayoutManager(getApplicationContext());
flexboxLayoutManager.setJustifyContent(JustifyContent.SPACE_BETWEEN);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(flexboxLayoutManager);
And for managing layout I used FlexBoxLayoutManager
which you can find more about it here and if you intend to use it, read the docs and use proper configuration for it. But you could use any other layout managers you wish.
Hope this was helpful for you.
Upvotes: 2