I'm trying to use a viewpager2 to show pictures taken from my app. Right now, I'm just using photos currently on my device to test, although the tutorial I followed (https://www.geeksforgeeks.org/viewpager2-in-android-with-example/) showed me how to make a viewpager2 with premade resource files. I'm trying to use an image bitmap instead, although whenever I run the code, the images come out blank. Is it an error with my files or is there a problem in my code? Here is my code:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
class ViewPager2Adapter extends RecyclerView.Adapter<ViewPager2Adapter.ViewHolder> {
// Array of images
// Adding images from drawable folder
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/DCIM/yes/yes_20220809_095311.jpg");
Bitmap bitmap2 = BitmapFactory.decodeFile("/sdcard/DCIM/yes/yes_20220809_095311___WITHTEXT.jpg");
private Bitmap[] images = {bitmap, bitmap2};
private Context ctx;
// Constructor of our ViewPager2Adapter class
ViewPager2Adapter(Context ctx) {
this.ctx = ctx;
}
// This method returns our layout
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(ctx).inflate(R.layout.images_holder, parent, false);
return new ViewHolder(view);
}
// This method binds the screen with the view
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
// This will set the images in imageview
holder.images.setImageBitmap(images[position]);
}
// This Method returns the size of the Array
#Override
public int getItemCount() {
return images.length;
}
// The ViewHolder class holds the view
public static class ViewHolder extends RecyclerView.ViewHolder {
ImageView images;
public ViewHolder(#NonNull View itemView) {
super(itemView);
images = itemView.findViewById(R.id.images);
}
}
}
PS: I am currently using hard coded files for testing, this will be changed later. The problem might be that the file path is wrong, but that is why I am asking this question.
Related
I am working on simple color picker in Android. I've setup Android Array String Resource for colors:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="color_picker_palette">
<item>#fff44336</item>
<item>#ffe91e63</item>
<item>#ff9c27b0</item>
<item>#ff673ab7</item>
<item>#ff3f51b5</item>
<item>#ff2196f3</item>
<item>#ff03a9f4</item>
<item>#ff00bcd4</item>
<item>#ff009688</item>
<item>#ff4caf50</item>
<item>#ff8bc34a</item>
<item>#ffcddc39</item>
<item>#ffffeb3b</item>
<item>#ffffc107</item>
<item>#ffff9800</item>
<item>#ffff5722</item>
<item>#ff795548</item>
<item>#ff9e9e9e</item>
<item>#ff607d8b</item>
<item>#ffbcaaa4</item>
<item>#ffeeeeee</item>
<item>#ffb0bec5</item>
</string-array>
</resources>
I import these colors through my populateFetchedColors() method:
private void populateFetchedColors()
{
String[] colorsArray=getResources().getStringArray(R.array.color_picker_palette);
if(fetchedColors==null)
{
this.fetchedColors=new ArrayList<ColorPickerFragmentAdapterRecord>();
}
else
{
this.fetchedColors.clear();
}
for(int colorIndex=0; colorIndex<colorsArray.length-1; colorIndex++)
{
ColorPickerFragmentAdapterRecord colorRecord=new ColorPickerFragmentAdapterRecord(colorsArray[colorIndex]);
this.fetchedColors.add(colorRecord);
}
}
which workss fine, I've double checked via Android Studio Debugger. Now, I had to create custom ArrayAdapter, named ColorPickerFragmentAdapter:
package com.example.exmapleapp1.colorpicker;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import androidx.annotation.NonNull;
import com.example.R;
import java.util.ArrayList;
public class ColorPickerFragmentAdapter extends ArrayAdapter<ColorPickerFragmentAdapterRecord> implements View.OnClickListener
{
private final ArrayList<ColorPickerFragmentAdapterRecord> dataSource;
private final Context adapterContext;
private static class ViewHolder
{
Button coloredButton;
}
public ColorPickerFragmentAdapter(#NonNull Context context,
int resource,
#NonNull ArrayList<ColorPickerFragmentAdapterRecord> objects)
{
super(context,
resource,
objects);
this.adapterContext=context;
this.dataSource=objects;
}
#Override
public void onClick(View v)
{
}
#Override
public View getView(int position,
View convertView,
ViewGroup parent)
{
ColorPickerFragmentAdapterRecord item=this.getItem(position);
ViewHolder viewHolder;
if(convertView==null)
{
viewHolder=new ViewHolder();
LayoutInflater inflater=LayoutInflater.from(this.getContext());
convertView=inflater.inflate(R.layout.color_picker_delegate_layout,
parent,
false);
viewHolder.coloredButton=(Button)convertView.findViewById(R.id.coloredButton);
convertView.setTag(viewHolder);
}
else
{
viewHolder=(ViewHolder)convertView.getTag();
}
viewHolder.coloredButton.setBackgroundColor(Integer.parseInt(item.getColorName()));
return convertView;
}
}
When I run this whole app, my buttons are listed just fine, however, they are all of same color, which it can be seen from screenshot:
What did I miss?
Hej KernelPanic,
setBackgroundColor requires a ColorInt. I think instead of Integer.parseInt(color) you must call item.getColorName().toColorInt()
Damn, I've set the wrong adapter:
this.colorsGridView.setAdapter(this.fetchedColorsAdapter);
is wrong, the real ArrayAdapter used is:
this.colorsGridView.setAdapter(this.dataSource);
And I've also changed colors to #rrggbb format, I had #aarrggbb format in colors_palette.xml as you can see:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="color_picker_palette">
<item>#f44336</item>
<item>#e91e63</item>
<item>#9c27b0</item>
<item>#673ab7</item>
<item>#3f51b5</item>
<item>#2196f3</item>
<item>#03a9f4</item>
<item>#00bcd4</item>
<item>#009688</item>
<item>#4caf50</item>
<item>#8bc34a</item>
<item>#cddc39</item>
<item>#ffeb3b</item>
<item>#ffc107</item>
<item>#ff9800</item>
<item>#ff5722</item>
<item>#795548</item>
<item>#9e9e9e</item>
<item>#607d8b</item>
<item>#bcaaa4</item>
<item>#eeeeee</item>
<item>#b0bec5</item>
</string-array>
</resources>
and changed parsing of color to:
viewHolder.coloredButton.setBackgroundColor(Color.parseColor(item.getColorName()));
Now it works:
I've spent som time trying to fix it, but my app works fine except for the images that don't load into my recyclerview. I tried with and without firebase database to get the images but in both case i don't get them.
However i get all my texts so i don't understand where the problem comes from. I searched for quite a time and didn't see anything that i didn't do in other tutorials/helps.
In my logcat i get the following errors :
2021-05-27 20:31:25.445 22716-22716/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2021-05-27 20:31:25.447 22716-22716/? E/Zygote: accessInfo : 1
And in the case of firebase Database i get the previous errors plus this one :
E/RecyclerView: No adapter attached; skipping layout
I put here my code so you can check if you need
Activity class :
package fr.balizok.pizzaapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import java.util.ArrayList;
import java.util.List;
import fr.balizok.pizzaapplication.adapter.PizzaAdapter;
public class MainActivity extends AppCompatActivity {
List<PizzaModel> pizzaList = new ArrayList<PizzaModel>();
RecyclerView recyclerViewPizzas;
PizzaAdapter pizzaAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pizzaList.add(new PizzaModel(
"Margherita",
"Sauce tomate, Mozarella",
"5.80€",
"https://cdn.pixabay.com/photo/2020/06/08/16/49/pizza-5275191_960_720.jpg"));
pizzaList.add(new PizzaModel(
"Savoyarde",
"Sauce tomate, Mozarella, Pomme de terre, Fromage",
"10.20€",
"https://cdn.pixabay.com/photo/2017/11/23/16/57/pizza-2973200_960_720.jpg"));
pizzaList.add(new PizzaModel(
"Poulet pesto",
"Sauce tomate, Mozarella, Poulet, Pesto",
"8.50€",
"https://cdn.pixabay.com/photo/2016/06/08/00/03/pizza-1442945_960_720.jpg"));
pizzaList.add(new PizzaModel(
"4 Saisons",
"Sauce tomate, Mozarella, Olive, Basilic, Jambon, Champignons, Artichaut",
"9.60€",
"https://cdn.pixabay.com/photo/2016/06/08/00/03/pizza-1442946_960_720.jpg"));
recyclerViewPizzas = findViewById(R.id.recyclerViewPizzas);
recyclerViewPizzas.setHasFixedSize(true);
recyclerViewPizzas.setLayoutManager(new LinearLayoutManager(this));
pizzaAdapter = new PizzaAdapter(MainActivity.this, pizzaList);
recyclerViewPizzas.setAdapter(pizzaAdapter);
recyclerViewPizzas.addItemDecoration(new PizzaItemDecoration());
}
}
Adapter class :
package fr.balizok.pizzaapplication.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.List;
import fr.balizok.pizzaapplication.PizzaModel;
import fr.balizok.pizzaapplication.R;
public class PizzaAdapter extends RecyclerView.Adapter<PizzaAdapter.ViewHolder>{
Context context;
List<PizzaModel> pizzaList;
public PizzaAdapter(Context context, List<PizzaModel> pizzaList) {
this.context = context;
this.pizzaList = pizzaList;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.menu_pizza_design,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull PizzaAdapter.ViewHolder holder, int position) {
PizzaModel currentPizza = pizzaList.get(position);
holder.pizza_name.setText(currentPizza.getName());
holder.ingredients.setText(currentPizza.getIngredients());
holder.price.setText(currentPizza.getPrice());
Glide.with(context).load(currentPizza.getImageURL()).into(holder.pizza_image);
}
#Override
public int getItemCount() {
return pizzaList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView pizza_image;
TextView pizza_name, ingredients, price;
public ViewHolder(#NonNull View itemView) {
super(itemView);
pizza_image = itemView.findViewById(R.id.pizza_image);
pizza_name = itemView.findViewById(R.id.pizza_name);
ingredients = itemView.findViewById(R.id.ingredients);
price = itemView.findViewById(R.id.price);
}
}
}
Hope you can help me, thank you in advance !
I follow your code and make it demo its resolved by using Picasso library.
Try this one I hope it would be helpful to you.
Picasso.get()
.load(currentPizza.getImageURL())
.resize(600, 200) // resizes the image to these dimensions (in pixel) if you want
.centerInside()
.into(holder.pizza_image);
Background - New to Android, but pretty nifty with moving layouts around, understanding Java, Kotlin and XML. However this task seems to be way above my head.
Problem - I'm looking to convert the following Java file (RecyclerView) into a Kotlin file (ViewPager) - since I already have a ViewPager hooked-up with the same scrolling behaviour as desired. I get the impression it's a 10min job for a seasoned developer. If that's the case I wonder if I could call upon some assistance from the community? At least to work out where to start. I can't seem to find a guide on how to convert a RecyclerView into a PagerAdapter or ViewPager.
Essentially the existing ViewPager I'm using has static data (5 items) and this one could have tens of items, so needs to be dynamic with a separate datasource (items of CardItem).
RecyclerViewAdapter - Current (Java)
package com.APPNAME.fragments.cards;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import com.APPNAME.R;
import com.APPNAME.databinding.FragmentCardsRecentlyViewedBinding;
import com.APPNAME.model.cardItem.CardItem;
public class RecentlyViewedAdapter extends RecyclerView.Adapter<RecentlyViewedAdapter.RecentlyViewedViewHolder> {
public OnCardClicked listener;
private ArrayList<CardItem> items = new ArrayList<>();
public void addItems(ArrayList<CardItem> list) {
items = list;
notifyDataSetChanged();
}
#Override
public RecentlyViewedViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
FragmentCardsRecentlyViewedBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.fragment_cards_recently_viewed, parent, false);
return new RecentlyViewedViewHolder(binding);
}
#Override
public void onBindViewHolder(RecentlyViewedViewHolder holder, int position) {
holder.binding.setViewModel(new RecentlyViewedViewModel(items.get(position)));
}
#Override
public int getItemCount() {
return items.size();
}
interface OnCardClicked {
void onCardClicked(View view, CardItem cardItem);
}
class RecentlyViewedViewHolder extends RecyclerView.ViewHolder {
FragmentCardsRecentlyViewedBinding binding;
public RecentlyViewedViewHolder(FragmentCardsRecentlyViewedBinding itemView) {
super(itemView.getRoot());
binding = itemView;
binding.cardView.setOnClickListener(v -> {
if (listener != null) {
listener.onCardClicked(v, items.get(getAdapterPosition()));
}
});
}
}
}
ViewPagerAdapter - Future (Kotlin)
package com.APPNAME.fragments.cards
import android.support.annotation.DrawableRes
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import java.util.*
import kotlinx.android.synthetic.main.fragment_cards_recently_viewed.view.*
import com.APPNAME.R
import com.APPNAME.activities.BaseActivity
import com.APPNAME.activities.cards.NewCardActivity
import com.APPNAME.model.cardItem.CardItem
import com.APPNAME.views.wrapContentViewPager.ObjectAtPositionPagerAdapter
class RecentlyViewedItemAdapter constructor(private val activity: BaseActivity) : ObjectAtPositionPagerAdapter() {
private var items = ArrayList<CardItem>()
override fun instantiateItemObject(container: ViewGroup, position: Int) : Any {
return getImageView(container, R.drawable.placeholder_card_image) { NewCardActivity.start(activity, it) }
}
private fun getImageView(container: ViewGroup, #DrawableRes imageResourceId: Int, onClick: (imageResourceId: Int) -> Unit = {}): View {
val layoutInflater = LayoutInflater.from(container.context)
val layout = layoutInflater.inflate(R.layout.fragment_cards_recently_viewed, container, false)
val image = layout.recentlyViewedImage
image.setImageResource(imageResourceId)
image.setOnClickListener { onClick(imageResourceId) }
container.addView(layout)
return layout
}
override fun isViewFromObject(view: View, anObject: Any) = (view == anObject)
override fun getCount() = 5 //Placeholder
override fun destroyItemObject(container: ViewGroup, position: Int, view: Any) {
container.removeView(view as View)
}
}
If you have relatively large number of items and need views to be recycled then the RecyclerView is the right option for you. It will be definitely easier than creating a custom view pager adapter with a fixed item count and a view holder pattern.
The default/generic PageAdapter is not recycling anything - it's added to make sure you have all your views initiated and ready to swipe through. However, you can use https://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html that will destroy/recreate the fragments when no longer used or reused.
Job done. I actually surprised myself by being able to modify the recycler view to mimmick the PageView's behaviour precisely (including padding, snap scrolling etc). Thanks to the simple subclass SnapHelper. Saved me a tonne of work, so no need to refactor the codebase.
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
PagerSnapHelper solved my problem.
binding.recyclerViewHomeAnnouncement.apply {
layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
binding.recyclerViewHomeAnnouncement.layoutManager = layoutManager
setHasFixedSize(true)
itemAnimator = DefaultItemAnimator()
adapter = homeAnnouncementAdapter
}
val snapHelper: SnapHelper = PagerSnapHelper()
snapHelper.attachToRecyclerView(binding.recyclerViewHomeAnnouncement)
I am trying to display CardViews inside a RecyclerView, each card will represent a cheese object.
This cheese object has 6 instance variables.
This is my Cheese.java :
public class Cheese {
private String CheeseName;
private String CheeseCountryOfOrigin;
private String CheeseDayMade;
private String CheeseDayExpire;
private String CheeseDescription ;
private String CheesePrice;
public Cheese(){} //Required for firebase
public Cheese(String CheeseName, String CheeseCountryOfOrigin, String CheeseDayMade, String CheeseDayExpire, String CheeseDescription, String CheesePrice) {
this.CheeseName = CheeseName;
this.CheeseCountryOfOrigin = CheeseCountryOfOrigin;
this.CheeseDayMade = CheeseDayMade;
this.CheeseDayExpire = CheeseDayExpire;
this.CheeseDescription = CheeseDescription;
this.CheesePrice = CheesePrice;
}
public String getCheeseName() {
return CheeseName;
}
public String getCheeseCountryOfOrigin() {
return CheeseCountryOfOrigin;
}
public String getCheeseDayMade() {
return CheeseDayMade;
}
public String getCheeseDayExpire() {
return CheeseDayExpire;
}
public String getCheeseDescription() {
return CheeseDescription;
}
public String getCheesePrice() {
return CheesePrice;
}
}
and this is my cheese_card.xml (I hardcoded some android:text for better understanding): cheese_card.xml
my RecyclerView is in a fragment.
This is my fragment:
fragment_cheeses_list.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/cheeses_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
</android.support.v7.widget.RecyclerView>
all my cheese items are already in my Firebase Real-Time Database. To make my life simpler I am trying to use FirebaseUI to populate my RecyclerView with data from my Firebase database.
This is my CheesesListFragment.java, which is displayed in my MainActivity:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.CardView;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.firebase.ui.database.FirebaseRecyclerOptions;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
public class CheeseListFragment extends Fragment {
private static final String TAG = "CheesesListFragment";
private FirebaseDatabase aFirebaseDatabase;
private DatabaseReference aCheesesDatabaseReference;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.e(TAG, "onCreateView Started Successfully");
//Create the recycler view object
RecyclerView cheesesRecycler = (RecyclerView) inflater.inflate(R.layout.fragment_cheeses_list, container, false);
//Add a grid layout manager to the recycler view
GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), 1);
cheesesRecycler.setLayoutManager(layoutManager);
cheesesRecycler.setHasFixedSize(true);
aFirebaseDatabase = FirebaseDatabase.getInstance();
aCheesesDatabaseReference = aFirebaseDatabase.getReference().child("cheeses");
//Query the cheeses in firebase db using firebaseUI instead of addChildEventListener
Query query = aCheesesDatabaseReference;
//configuration for the FirebaseRecyclerAdapter
FirebaseRecyclerOptions<Cheese> options =
new FirebaseRecyclerOptions.Builder<Cheese>()
.setQuery(query, Cheese.class)
.build();
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Cheese, CheeseViewHolder>(options) {
#Override
public CheeseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Create a new instance of the ViewHolder, in this case we are using a custom
// layout called R.layout.cheese_card for each item
CardView cv = (CardView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.cheese_card, parent, false);
return new CheeseViewHolder(cv);
}
#Override
protected void onBindViewHolder(CheeseViewHolder holder, int position, Cheese model) {
CheeseViewHolder myHolder = (CheeseViewHolder)holder;
myHolder.cheeseName.setText(model.getCheeseName());
myHolder.cheeseCountryOfOrigin.setText(model.getCheeseCountryOfOrigin());
myHolder.cheeseDayMade.setText(model.getCheeseDayMade());
myHolder.cheeseDayExpire.setText(model.getCheeseDayExpire());
myHolder.cheeseDescription.setText(model.getCheeseDescription());
myHolder.cheesePrice.setText(model.getCheesePrice());
}
};
//Set the adapter to the recycle View
cheesesRecycler.setAdapter(adapter);
return cheesesRecycler;
}
public static class CheeseViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
TextView CheeseName;
TextView CheeseCountryOfOrigin;
TextView CheeseDayMade;
TextView CheeseDayExpire;
TextView CheeseDescription;
TextView CheesePrice;
public CheeseViewHolder (CardView v){
super(v);
cardView = v;
CheeseName = (TextView)cardView.findViewById(R.id.cheese_name);
CheeseCountryOfOrigin= (TextView)cardView.findViewById(R.id.cheese_origin);
CheeseDayMade= (TextView)cardView.findViewById(R.id.cheese_day_made);
CheeseDayExpire= (TextView)cardView.findViewById(R.id.cheese_day_expire);
CheeseDescription= (TextView)cardView.findViewById(R.id.cheese_description);
CheesePrice= (TextView)cardView.findViewById(R.id.cheese_price);
}
}
}
So my questions are: (answering any of them is welcomed and very helpful)
If i get it right, onCreateViewHolder is supposed to make ViewHolders for my Cheese object using my cheese_card.xml . if so, assuming I delete onBindingViewHolder am I suppose to see lots of view holders that look like my cheese_card.xml?
in onBindingViewHolder in setText : how can I get my TextViews to get a value from my firebase?
I am new to programming and not sure about onCreateViewHolder, onBindingHolder and cheesesViewHolder.I am not sure what every code I writed there means as some of them are copy-pasted.If I got it all wrong, can you please explain how can I reach my desired outcome, and what I did wrong?
Thank you, in advance :)
Modify onBindingViewHolder and cheesesViewHolder. Because in onBindingViewHolder you will bind data with Views not Views with they ids. Bind Views with they ids inside cheesesViewHolder. For example:
CardView cardView;
TextView cheese_name;
TextView cheese_origin;
public CheeseViewHolder(CardView v) {
super(v);
cardView = v;
cheese_name = (TextView) cardView.findViewById(R.id.cheese_name);
cheese_origin = (TextView) cardView.findViewById(R.id.cheese_origin);
// and so on...
}
Then inside onBindingViewHolder you will do something like this:
#Override
protected void onBindViewHolder(CheeseViewHolder holder, int position, Cheese model) {
cheesesViewHolder myHolder = (cheesesViewHolder)holder;
myHolder.cheese_name.setText(model.getCheeseName());
myHolder. cheese_origin.setText(model.getCheeseOrigin());
//and so on...
}
I was able to eventually fix my problem and get onCreateViewHolder and onBindViewHolder to start simply by adding
adapter.startListening();
to my onStart method. like this:
#Override
public void onStart() {
super.onStart();
Log.e(TAG,"onStart Started Successfully");
adapter.startListening();
}
And I edited the code using #Yupi suggestion.
my problem is - how to create custom list view with not just repeating one custom view, but like in Instagram or other app where list include other views in it, which it looks like scroll view with list view android other views in it, but Roman Guy says "List View in a Scroll view is a very poor way", and I'm agreed with it, don't believe which is Google use this way...
What are the best way to achieve this thing with ListView or Recycler View
To achieve that UI, you must define multiple view types for your Listview or Recyclerview; a very similar question has been answered here.
In your example, you will have two view types:
<Horizontal Scroll> which is an embedded horizontal Recyclerview/Listview.
<View> which is a view type that you have defined.
There are many tutorials on this concept. I would recommend you to use Recyclerview in your implementation due to its advantages over Listview.
Hey this is how your main fragment will look like :
package com.leoneo.stackoverflow;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.soulpatch.stackoverflow.R;
import java.util.ArrayList;
public class RecyclerViewExample extends Fragment {
private ArrayList<Object> mValues = new ArrayList<>();
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final RecyclerView recyclerView = inflater.inflate(R.layout.recycler_view_example, container, false);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
final MultpleItemAdapter adapter = new MultpleItemAdapter(mValues);
recyclerView.setAdapter(adapter);
return recyclerView;
}
}
And here's your adapter code.
package com.leoneo.stackoverflow;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.soulpatch.stackoverflow.R;
import java.util.ArrayList;
public class MultpleItemAdapter extends RecyclerView.Adapter<MultpleItemAdapter.ViewHolder> {
private ArrayList<Object> mValues = new ArrayList<>();
public MultpleItemAdapter(ArrayList<Object> values) {
mValues = values;
}
enum ItemType {
TYPE_A,
TYPE_B;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case 1:
//Inflate Type A layout
final LinearLayout linearLayoutA = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_a, parent, false);
//And pass the view to the ViewHolder
return new ViewHolder(linearLayoutA);
break;
case 2:
//Inflate Type B layout
final LinearLayout linearLayoutB = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_b, parent, false)
//And pass the view to the ViewHolder
return new ViewHolder(linearLayoutB);
break;
}
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (getItemViewType(position)) {
case 1:
final TypeA typeA = (TypeA) mValues.get(position);
//Deal with the views that you defined for LinearLayout A
break;
case 2:
final TypeB typeB = (TypeB) mValues.get(position);
//Deal with the views that you defined for LinearLayout B
break;
}
}
#Override
public int getItemCount() {
return mValues.size();
}
#Override
public int getItemViewType(int position) {
final Object obj = mValues.get(position);
if (obj instanceof TypeA) {
return ItemType.TYPE_A.ordinal();
} else if (obj instanceof TypeB) {
return ItemType.TYPE_B.ordinal();
}
return super.getItemViewType(position);
}
static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
//Class that I want to be displayed in a CardView
private class TypeA {
}
//Class that I want to be displayed in a a LinearLayout
private class TypeB {
}
}
You can have as many classes as you want like TypeA and TypeB and add types to ItemType class as well accordingly.
Rest should be pretty self explanatory assuming you've worked with RecyclerViews before.
You are looking for different View types. It's possible with using these
GetViewTypeCount() this is an overridable method which returns how many view type you have in your listview-recycleview.
getItemViewType(int pos) get which item view type should return at the given position
For example if you want to add a different view in every 10 item, and there is only 2 type of views, you should use a code like this:
#Override
public int getItemViewType(int position){
if (position % 10 == 0)
return SECOND_ITEM;
return FIRST_ITEM;
}
#Override
public int getViewTypeCount() {
return 2;
}
And at the getView() function you can handle it with a switch-case or if-else structure like this:
switch (getItemViewType(cursor.getPosition())) {
case SECOND_ITEM:
//something to do
break;
default:
//something to do
}
You might want to use 2 different layout file to inflate in the switch-case statement above. However, if the layouts of both items are not different that much, I recommend to create just 1 layout, and make views inside it visible and gone according to item you want to get.
Oh and in case you don't know where to use them, you use them at your adapter class. The functions may vary as which kind of adapter you use however, they all work with the same logic.
And finally, I recommend you to use recyclerview. It is just a bit harder to implement than listview but it is a great substitution of listview which is more powerful and flexible. You can do a research for it.
Here is how you can achieve this like instagram, facebook etc. : You inflate a scrollable view at the given positions.
I hope the answer helps.
As always,
Have a nice day.