I am trying to populate a recyclerview inside the Fragment under a TabLayout. Everything seems to be fine, but the data is not actually populated in the recyclerview, while all the content Logs[Log.e();] is working fine. Can anyone relate the issue ?
My Fragment Is Like :
public class SugarLevelReport extends Fragment
{
private ConstraintLayout view_constraintLayout;
private RecyclerView blood_sugar_recyclerView;
private ProgressBar progressBar;
private ArrayList<PatientRecordModel> patientRecordModelArrayList = new ArrayList<PatientRecordModel>();
private RecyclerView.Adapter bloodSugaradapter;
// for intent data
public String patient_id_from_intent, patient_name_from_intent, patient_dob_from_intent, patient_mobile_from_intent, patient_email_from_intent;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_sugar_level_report, container, false);
findViewById(view);
return view;
}
public void findViewById(View view)
{
view_constraintLayout = (ConstraintLayout)view.findViewById(R.id.view_constraintLayout);
/*progressBar = (ProgressBar)view.findViewById(R.id.progressBar);*/
blood_sugar_recyclerView = (RecyclerView)view.findViewById(R.id.blood_sugar_recyclerView);
blood_sugar_recyclerView.setHasFixedSize(true);
blood_sugar_recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
bloodSugaradapter = new SugarLevelReportAdapter(getActivity(), patientRecordModelArrayList);
blood_sugar_recyclerView.setAdapter(bloodSugaradapter);
loadData();
}
public void loadData()
{
if(GlobalMethods.isNetworkConnected(getActivity()))
{
String[] names = getResources().getStringArray(R.array.names);
for (int i = 0 ; i < names.length ; i++)
{
PatientRecordModel patientRecordModel = new PatientRecordModel();
patientRecordModel.setPatient_name(names[i]);
// log here is working fine , and its giving correct data
Log.e("patientsName", patientRecordModel.getPatient_name());
patientRecordModelArrayList.add(patientRecordModel);
bloodSugaradapter.notifyDataSetChanged();
}
}
else
{
}
}
Adapter Class
public class SugarLevelReportAdapter extends RecyclerView.Adapter<SugarLevelReportAdapter.SugarLevelReportHolder>{
public Context context;
public ArrayList<PatientRecordModel> patientRecordModelArrayList = new ArrayList<PatientRecordModel>();
public SugarLevelReportAdapter(Context context, ArrayList<PatientRecordModel> patientRecordModelArrayList)
{
this.context = context;
this.patientRecordModelArrayList = patientRecordModelArrayList;
}
#Override
public SugarLevelReportHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.sugar_level_report_cardview, parent, false);
SugarLevelReportHolder sugarLevelReportHolder = new SugarLevelReportHolder(view);
return sugarLevelReportHolder;
}
#Override
public void onBindViewHolder(SugarLevelReportHolder holder, int position)
{
PatientRecordModel patientRecordModel = patientRecordModelArrayList.get(position);
Log.e("patient_name",patientRecordModel.getPatient_name());
holder.patient_name_textView.setText(patientRecordModel.getPatient_name());
}
#Override
public int getItemCount()
{
return patientRecordModelArrayList.size();
}
public static class SugarLevelReportHolder extends RecyclerView.ViewHolder
{
public TextView month_textView, date_textView, year_textView;
public TextView patient_name_textView, patient_count_textView, meal_type_textView;
public ImageView overflow_menu_imageView;
public SugarLevelReportHolder(View itemView)
{
super(itemView);
month_textView = (TextView)itemView.findViewById(R.id.month_textView);
date_textView = (TextView)itemView.findViewById(R.id.date_textView);
year_textView = (TextView)itemView.findViewById(R.id.year_textView);
patient_name_textView = (TextView)itemView.findViewById(R.id.patient_name_textView);
patient_count_textView = (TextView)itemView.findViewById(R.id.patient_count_textView);
meal_type_textView = (TextView)itemView.findViewById(R.id.meal_type_textView);
overflow_menu_imageView = (ImageView)itemView.findViewById(R.id.overflow_menu_imageView);
}
}
}
xml code [fragment_sugar_level_report.xml]
<android.support.constraint.ConstraintLayout
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/blood_sugar_recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:scrollbars="vertical"
android:scrollbarSize="1dp"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp">
</android.support.v7.widget.RecyclerView>
So I had a similar problem on my current project. I cannot tell you why it happens but to solve it you need to move the part for updating data to the adapter.
on your adapter create the following method:
public void updateData(List<PatientRecordModel> list){
patientRecordModelArrayList = list;
notifyDatasetChanged();
}
On you Fragment class when you want to update the data just call
bloodSugaradapter.updateData(patientRecordModel);
On the same it is advisable to load your views onViewCreated instead of onCreateView. Also use a data mapping library such as GSON or or jackson to improve speed and reliability in data mapping.See a comparison here Hope this helps
Related
I have implemented a RecyclerView and customer Adapter many times, but for some reason I cannot get this one to display any data. I am feeding in data from JSON using retrofit and calling notifyDataSetChanged() once this has been loaded, yet it still remains blank. I have stripped this back to just one text view to try and simplify but still not getting anything. Can anyone see where I am going wrong here?
When I debug, I am getting the List to contain data so I am definitely parsing the data correctly, I just cant get it display in the recycler view. I have even checked the list.size() in the loadTrailerList method and it has data.
My Activity onCreate method:
trailerAdapter = new TrailerAdapter(this);
trailerRecyclerView = findViewById(R.id.trailer_recycler_view);
trailerRecyclerView.setLayoutManager(new LinearLayoutManager(this));
trailerRecyclerView.setAdapter(trailerAdapter);
Retrofit onResponse method:
if (response.body() != null) {
trailers = response.body().getTrailers();
}
trailerAdapter.loadTrailerList(response.body().getTrailers());
My custom adapter:
public class TrailerAdapter extends RecyclerView.Adapter<TrailerAdapter.TrailerViewHolder> {
private final List<Trailer> trailerList = new ArrayList<>();
private final TrailerClickListener listener;
public TrailerAdapter(TrailerClickListener listener) {
this.listener = listener;
}
#NonNull
#Override
public TrailerViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.trailer_list_item, viewGroup, false);
return new TrailerViewHolder(itemView, this);
}
#Override
public void onBindViewHolder(#NonNull TrailerViewHolder trailerViewHolder, int i) {
trailerViewHolder.trailerTitle.setText(trailerList.get(i).getName());
}
#Override
public int getItemCount() {
return trailerList.size();
}
public void loadTrailerList(List<Trailer> trailers) {
this.trailerList.clear();
if (trailers != null) {
trailers.addAll(trailers);
}
notifyDataSetChanged();
}
class TrailerViewHolder extends RecyclerView.ViewHolder {
final TrailerAdapter trailerAdapter;
private final TextView trailerTitle;
private TrailerViewHolder(#NonNull View itemView, TrailerAdapter trailerAdapter) {
super(itemView);
this.trailerAdapter = trailerAdapter;
trailerTitle = itemView.findViewById(R.id.text_view_trailer_title);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onTrailerClicked(trailerList.get(getAdapterPosition()));
}
});
}
}
}
My List Item XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text_view_trailer_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Play Trailer" />
</LinearLayout>
the recycler view in my activity XML:
<android.support.v7.widget.RecyclerView
android:id="#+id/trailer_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
app:layout_constraintTop_toBottomOf="#+id/trailer_divider">
</android.support.v7.widget.RecyclerView>
I am grateful for anyone that can point me in the right direction
It is because you are sending a list to adapter but, you are not initializing your list which is used in the adapter.
try this.
public void loadTrailerList(List<Trailer> trailers) {
this.trailerList.clear();
if (trailers != null) {
trailerList = trailers;
}
notifyDataSetChanged();
}
Doh! I just realised what I was doing wrong:
In my loadTrailerList() method in my adapter, I was calling:
trailers.addAll(trailers);
instead of:
trailerList.addAll(trailers);
to load the list of items into the actual ArrayList! whoops!
I've written this code for my recycler view, but it doesn't seem to work (it gives to me some errors)... Can someone tell me what I do wrong?
CustomAdapter.java:
public class CustomAdapter extends RecyclerView.Adapter<CustomViewHolder> {
//Attributi:
private Context context;
private int[] immagineDio;
private String[] nomeDio;
//Costruttori:
public CustomAdapter(Context context, int[] immagineDio, String[] nomeDio){
this.context = context;
this.immagineDio = immagineDio;
this.nomeDio = nomeDio;
}
//Metodi di istanza:
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return CustomViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_item, parent, false));
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
holder.bind(immagineDio[position], nomeDio[position]);
}
#Override
public int getItemCount() {
return nomeDio.length;
}
}
CustomViewHolder.java:
public class CustomViewHolder extends RecyclerView.ViewHolder {
ImageView mFlag;
TextView mName;
public CustomViewHolder(#NonNull View itemView) {
super(itemView);
mFlag = itemView.findViewById(R.id.imageView);
mName = itemView.findViewById(R.id.textView);
}
//binding data with UI
void bind(int imageId, String name) {
mFlag.setImageResource(imageId);
mName.setText(name);
} }
ListViewActivity.java:
public class ListViewActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_layout);
String[] nomeDei = {"Baldr","Borr","Bragi","Dagr","Dellingr","Eir","Eostre","Forseti","Freya","Freyr","Frigg","Fulla","Gefjun","Gerðr","Gullveig","Heimdallr","Hel","Hermóðr","Höðr","Hœnir","Iðunn","Itreksjóð","Jǫrð","Kvasir","Lóðurr","Lofn","Logi","Lýtir","Máni","Mímir","Móði","Nanna","Njörun","Njörðr","Nótt","Óðr","Rán","Ríg","Sága","Sif","Signe","Sigyn","Sinfjötli","Sjöfn","Skaði","Skirnir","Snotra","Sól","Syn","Thor","Týr","Ullr","Váli","Vár","Ve","Viðarr","Víli","Vör"};
int[] immagineDei = {
R.drawable.profilo_baldr,
R.drawable.profilo_borr,
R.drawable.profilo_bragi,
R.drawable.profilo_dagr,
R.drawable.profilo_dellingr,
R.drawable.profilo_eir,
R.drawable.profilo_eostre,
R.drawable.profilo_forseti,
R.drawable.profilo_freya,
R.drawable.profilo_freyr,
R.drawable.profilo_frigg,
R.drawable.profilo_fulla,
R.drawable.profilo_gefjun,
R.drawable.profilo_geror,
R.drawable.profilo_gullveig,
R.drawable.profilo_heimdallr,
R.drawable.profilo_hel,
R.drawable.profilo_hermoor,
R.drawable.profilo_hoor,
R.drawable.profilo_hoenir,
R.drawable.profilo_iounn,
R.drawable.profilo_itreksjoo,
R.drawable.profilo_joro,
R.drawable.profilo_kvasir,
R.drawable.profilo_loourr,
R.drawable.profilo_lofn,
R.drawable.profilo_logi,
R.drawable.profilo_lytir,
R.drawable.profilo_mani,
R.drawable.profilo_mimir,
R.drawable.profilo_modi,
R.drawable.profilo_nanna,
R.drawable.profilo_njorun,
R.drawable.profilo_njoror,
R.drawable.profilo_nott,
R.drawable.profilo_oor,
R.drawable.profilo_ran,
R.drawable.profilo_rig,
R.drawable.profilo_saga,
R.drawable.profilo_sif,
R.drawable.profilo_signe,
R.drawable.profilo_sigyn,
R.drawable.profilo_sinfjotli,
R.drawable.profilo_sjofn,
R.drawable.profilo_skaoi,
R.drawable.profilo_skirnir,
R.drawable.profilo_snotra,
R.drawable.profilo_sol,
R.drawable.profilo_syn,
R.drawable.profilo_thor,
R.drawable.profilo_tyr,
R.drawable.profilo_ullr,
R.drawable.profilo_vali,
R.drawable.profilo_var,
R.drawable.profilo_ve,
R.drawable.profilo_vidar,
R.drawable.profilo_vili,
R.drawable.profilo_vor,
};
ListView listViewReference = findViewById(R.id.listView);
CustomAdapter customAdapter = new CustomAdapter(ListViewActivity.this, immagineDei, nomeDei);
listViewReference.setAdapter(customAdapter); //this line gives an error
} }
listview_layout.xml:
<android.support.v7.widget.RecyclerView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
you have used RecyclerView in your XML file and try to getting ListView in Java code file try this
RecyclerView listViewReference = (RecyclerView )findViewById(R.id.listView);
This is a very detailed and good tutorial on how to implement the recyclerview. Please read it for better understanding. Hope it helps.
Summary:
Step 1: Below is the RecyclerView widget with necessary attributes.
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Step 2: Open build.gradle and add recycler view dependency. com.android.support:recyclerview-v7:{{latest version}} and rebuild the project.
Step 3: Create your CustomAdapter
Step 4: From your activity/fragment:
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mAdapter = new MoviesAdapter(movieList);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(mAdapter);
You have not used a Layout Manager for the recycler view
link
Recently I started coding my really first android project by using Android Studio 3.1.2.
Inside on one of my fragments, I have a recyclerview, in which I want to show data from a JSON API. For the items I created a custom layout which is intended to be used as a CardView.
I proceeded that far, that I receive my data, but my recyclerview remains empty. Also, if the json object is empty, or the API deosn't respond, the idea was to let the recyclerview automatically add an item, that tells the user that there's no data or the API was not available (would be cool, if I could use the same layout here, I created). This is how my code looks so far:
The raw structure of report_compact_card.xml (embedded in android.support.v7.widget.CardView):
<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="2dp"
app:cardCornerRadius="2dp">
<android.support.constraint.ConstraintLayout
android:id="#+id/linearLayout"
...>
<TextView
android:id="#+id/report_header_textview"
... />
<TextView
android:id="#+id/report_body_textview"
... />
<ImageView
android:id="#+id/report_icon_imageview"
... />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
My ReportCompactAdapter:
public class ReportCompactAdapter extends RecyclerView.Adapter<ReportCompactAdapter.ReportCompactViewHolder> {
private Context context;
private ArrayList<Report> reports;
public ReportCompactAdapter(Context context, ArrayList<Report> reports) {
this.context = context;
this.reports = reports;
}
#Override
public ReportCompactViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.report_compact_card, parent, false);
return new ReportCompactViewHolder(view);
}
#Override
public void onBindViewHolder(ReportCompactViewHolder holder, int position) {
//this is where I want to set a "no data" card
if (reports.isEmpty()) {
holder.reportBodyTextView.setText("Keine Meldungen");
holder.reportBodyTextView.setText(":)");
holder.reportIconImageView.setImageResource(R.drawable.ic_report_ok_24dp);
} else {
//here I want to fill my cards with my json data
Report currentReport = reports.get(position);
String currentId = currentReport.getId();
String currentTest = currentReport.getTest();
String currentTOpen = currentReport.getTOpen();
Employee currentEmployee = currentReport.getEmployee();
holder.reportHeaderTextView.setText(currentTest);
holder.reportBodyTextView.setText(currentId + " " + currentTOpen + " " + currentEmployee.getName());
holder.reportIconImageView.setImageResource(R.drawable.ic_report_err_24dp);
}
}
#Override
public int getItemCount() {
return reports.size();
}
public class ReportCompactViewHolder extends RecyclerView.ViewHolder {
public TextView reportHeaderTextView;
public TextView reportBodyTextView;
public ImageView reportIconImageView;
//this is where I try to access my layout
public ReportCompactViewHolder(View itemView) {
super(itemView);
reportHeaderTextView = itemView.findViewById(R.id.report_header_textview);
reportBodyTextView = itemView.findViewById(R.id.report_body_textview);
reportIconImageView = itemView.findViewById(R.id.report_icon_imageview);
}
}
}
Additionally in may OverviewFragment, where I use my recyclerview i'm doing like so:
public class OverviewFragment extends Fragment {
private ArrayList<Report> reports;
private RecyclerView reportRecyclerView;
private ReportCompactAdapter reportCompactAdapter;
private RequestQueue requestQueue;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_overview, container, false);
reports = new ArrayList<Report>();
//here I want to set up my recyclerview
reportRecyclerView = fragmentView.findViewById(R.id.report_recyclerview);
reportRecyclerView.setHasFixedSize(true);
reportRecyclerView.setLayoutManager(new LinearLayoutManager(this.getContext()));
//I already set the adapter here to avoid the warning that no adapter is attached
reportRecyclerView.setAdapter(new ReportCompactAdapter(this.getContext(), reports));
//I use volley for Request stuff
requestQueue = Volley.newRequestQueue(this.getContext());
//this guy is intended to fetch my json data
parseJSON();
return fragmentView;
}
private void parseJSON() {
JSONObjectRequest request = new JSONObjectRequest(Request.Method.GET, "myurl.com", null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray("reports");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject report = jsonArray.getJSONObject(i);
reports.add(new Report(json));
}
//here I set my adapter after parsing my data
reportCompactAdapter = new ReportCompactAdapter(OverviewFragment.this.getContext(), reports);
reportRecyclerView.setAdapter(reportCompactAdapter);
} catch(JSONException e) {
e.printStackTrace();
}
}
}, new Response.OnErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
requestQueue.add(request);
}
}
Because of some reason I didn't even get my "no data" card into my recyclerview, neither my filled cards, although "myurl.com" is valid and doesn't throw any error. So my question is, where did I mis a step to successfully squeeze my cards into my recyclerview? Thanks in forward!
You need return atleast 1 item in getItemCount() like below
#Override
public int getItemCount() {
return reports.size()==0?1:report.size();
}
So I am trying to create an android app on alcohol and mixers, but have been stuck on the following problem for a while now...
I want to display every alcohol category (eg: Gin, Vodka, Whiskey, etc..) in a RecyclerView that scrolls horizontally, and every alcohol type (eg: Bourbon and Scotch for the Whiskey Category) in a RecyclerView that scrolls vertically.
I have created one adapter for each RecyclerView (CategoryAdapter for the horizontal RecyclerView called category, and MixerAdapter for the vertical RecyclerView called categoryDetails).
So far I've managed to create and display category as desired, but have some difficulties for categoryDetails.
Basically, I can't figure out how to update the contents of categoryDetails when an item of category is selected:
For example
If the user selects Whiskey in category, I want categoryDetails to display Bourbon and Scotch.
If the user then selects Gin, I want categoryDetails to only display Gin and Flavoured Gin, etc...
I hope I've been clear enough on what it is I want to accomplish!
Any help would be much appreciated, thanks!!
Here is a screenshot of how the screen appears when the activity is loaded.
If a user selects Rum (white on black RecyclerView), I want the RecyclerView currently showing Gin and Flavored Gin (black on white RecyclerView) to show the alcohols associated with the Rum category.
Screenshot
Here is the XML file holding the two recyclerViews category and categoryDetails
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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"
tools:context=".TipsDrinks">
<android.support.v7.widget.RecyclerView
android:id="#+id/category"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="#android:color/black"
android:orientation="horizontal"
android:scrollbars="horizontal"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/SpinnerPrompt" >
</android.support.v7.widget.RecyclerView>
<android.support.v7.widget.RecyclerView
android:id="#+id/categoryDetails"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:background="#android:color/white"
android:orientation="horizontal"
android:scrollbars="vertical"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="#+id/adView4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/category"
app:layout_constraintVertical_bias="0.0">
</android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
The Class associated with the previous layout
public class TipsDrinks extends AppCompatActivity {
private CategoryAdapter categoryAdapter; // Adapter used for the category RecyclerView
public MixerAdapter mixerAdapter; //Adapter used for the categoryDetails RecyclerView
private RecyclerView categories; // The RecyclerView holding the name of each alcohol category
public RecyclerView catDetails; // The RecyclerView holding each type of that alcohol category
private DrinkMenu drinkMenu; // The DrinkMenu is another Class holding every Alcohol Category, the type of each alcohol and the mixers good with it
private ArrayList<String> drinkCat = new ArrayList<>(); // A String ArrayList holding the name of each alcohol category (Gin, Vodka, Rum, Whiskey, Other)
private ArrayList<Drink> drinkMixers = new ArrayList<>(); // A Drink(String, ArrayList<String>) ArrayList holding the mixers of every Drink
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tips_drinks);
categories = findViewById(R.id.category);
catDetails = findViewById(R.id.categoryDetails);
drinkMenu = new DrinkMenu();
setCategoryView(); // Creates the category RecyclerView
setDrinkMixers(); // Creates the categoryDetails RecyclerView
}
private void setCategoryView(){
categoryAdapter = new CategoryAdapter(drinkCat);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(TipsDrinks.this, LinearLayoutManager.HORIZONTAL, false);
categories.addItemDecoration(new DividerItemDecoration(TipsDrinks.this, DividerItemDecoration.HORIZONTAL));
categories.setLayoutManager(layoutManager);
categories.setItemAnimator(new DefaultItemAnimator());
categories.setAdapter(categoryAdapter);
prepareCategories();
}
private void prepareCategories(){
drinkCat.clear();
drinkCat.addAll(drinkMenu.getDrinkCategories());
for (String drink : drinkCat) {
System.out.println(drink);
}
categoryAdapter.notifyItemInserted(drinkCat.size() - 1);
}
private void setDrinkMixers() {
mixerAdapter = new MixerAdapter(drinkMixers);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
catDetails.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
catDetails.setLayoutManager(layoutManager);
catDetails.setItemAnimator(new DefaultItemAnimator());
catDetails.setAdapter(mixerAdapter);
prepareMixers();
}
private void prepareMixers() {
drinkMixers.clear();
drinkMixers.addAll(drinkMenu.getDrinkMixers(categoryAdapter.getCurrentCategory()));
mixerAdapter.notifyItemChanged(drinkMixers.size() -1);
}
}
The CategoryAdapter Class for the category RecyclerView
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.MyViewHolder> {
private List<String> drinkList; //A List of String holding the category for each drink
private String textName = "Gin";
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TextView name; // The TextView holding the name of the category
MyViewHolder(View view) {
super(view);
view.setOnClickListener(this);
name = view.findViewById(R.id.catName);
}
#Override
public void onClick(View v) {
//Code to update the contents of the categoryDetails RecyclerView
}
}
CategoryAdapter(ArrayList<String> drinkList) { this.drinkList = drinkList; }
#Override
public CategoryAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.category_text, parent, false);
return new MyViewHolder(itemView);
}
#SuppressLint("SetTextI18n")
#Override
public void onBindViewHolder(CategoryAdapter.MyViewHolder holder, int position) {
String drink = drinkList.get(position);
holder.name.setText(drink);
textName = holder.name.getText().toString();
}
#Override
public int getItemCount() {
return drinkList.size();
}
public String getCurrentCategory() {
return textName;
}
}
The MixerAdapter Class for the categoryDetails RecyclerView
public class MixerAdapter extends RecyclerView.Adapter<MixerAdapter.MyViewHolder>{
private List<Drink> mixerList;
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView mixerCat, mixers;
MyViewHolder(View view) {
super(view);
view.setOnClickListener(this);
mixerCat = view.findViewById(R.id.mixerCat2);
mixers = view.findViewById(R.id.mixers2);
}
#Override
public void onClick(View v) {
if (mixers.getVisibility() == mixerCat.getVisibility()) {
mixers.setVisibility(View.GONE);
}
else {
mixers.setVisibility(View.VISIBLE);
}
}
}
MixerAdapter(ArrayList<Drink> mixerList) {
this.mixerList = mixerList;
}
#Override
public MixerAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.drinks_row, parent, false);
return new MixerAdapter.MyViewHolder(itemView);
}
#SuppressLint("SetTextI18n")
#Override
public void onBindViewHolder(MixerAdapter.MyViewHolder holder, int position) {
Drink drink = mixerList.get(position);
StringBuilder mixerStringList = new StringBuilder("");
holder.mixerCat.setText(drink.getSorM());
for (String mixer: drink.getMixers()) {
mixerStringList.append(mixer).append("\n");
}
holder.mixers.setText(mixerStringList.toString().trim());
}
#Override
public int getItemCount() {
return mixerList.size();
}
}
Create a callback interface in CategoryAdapter. When user clicks on an item in Category RecycleView, it's activity responsibility to populate MixerAdapter with new items as per selection.
CategoryAdapter
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.MyViewHolder> {
private CategoryInterface callback;
CategoryAdapter(ArrayList<String> drinkList, CategoryInterface listener) {
this.drinkList = drinkList;
callback = listener;
}
#Override
public void onClick(View v) {
//Code to update the contents of the categoryDetails RecyclerView
callback.onItemSelected(getAdapterPosition());
}
public interface CategoryInterface {
void onItemSelected(int position);
}
}
Activity
public class TipsDrinks extends AppCompatActivity implements CategoryInterface {
private void setCategoryView(){
categoryAdapter = new CategoryAdapter(drinkCat, this);
}
#Override
void onItemSelected(int position) {
//Reassign items in MixerAdapter
}
}
that depends on your implementations , one global method which should work for all implementations is using HolderView method and using onTouchListener on the groups's root view
v.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
//the child should expand and be updated
}
return false;
}
});
I'm trying to figure out how to achieve the same effect of
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
in a RecyclerView implementation. Please help.
There is no built-in support for a "choice mode" structure with RecyclerView. Your options are to either roll it yourself or use a third-party library that offers it.
The DynamicRecyclerView library offers choice modes, but I have not tried it.
This sample app demonstrates implementing it yourself, in this case using the activated state to indicate which is the current choice. The overall pattern is:
Have your RecyclerView.ViewHolder detect a UI operation that indicates a choice (click on a row? click on a RadioButton in the row? etc.).
Keep track of the selection at the level of your RecyclerView.Adapter. In my case, a ChoiceCapableAdapter handles that, in conjunction with a SingleChoiceMode class that implements a ChoiceMode strategy.
When a choice is made, update the newly-chosen row to reflect the choice and update the previously-chosen row to reflect that it is no longer chosen. findViewHolderForPosition() on RecyclerView can help here -- if you track the position of the last choice, findViewHolderForPosition() can give you the ViewHolder for that choice, so you can "un-choose" it.
Keep track of the choice across configuration changes, by putting it in the saved instance state of the activity or fragment that is managing the RecyclerView.
I've created a library for this kind of choice mode applied to the RecyclerView, maybe it can help:
Description
This library has been created to help the integration of a multi-choice selection to the RecyclerView
Implementation
The integration with Gradle is very easy, you just need the jcenter repository and the library:
repositories {
jcenter()
}
...
dependencies {
compile 'com.davidecirillo.multichoicerecyclerview:multichoicerecyclerview:1.0.1'
}
Main steps for usage
Add the MultiChoiceRecyclerView to your xml file
<com.davidecirillo.multichoicesample.MultiChoiceRecyclerView
android:id="#+id/multiChoiceRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Instanciate you object and connect the view
MultiChoiceRecyclerView mMultiChoiceRecyclerView = (MultiChoiceRecyclerView) findViewById(R.id.multiChoiceRecyclerView);
Extend you adapter to the MultiChoiceAdapter and add it to the RecyclerView as per normal usage
public class MyAdapter extends MultiChoiceAdapter<MyViewHolder> {
public MyAdapter(ArrayList<String> stringList, Context context) {
this.mList = stringList;
this.mContext = context;
}
...
}
MyAdapter myAdapter = new MyAdapter(mList, getApplicationContext());
mMultiChoiceRecyclerView.setAdapter(myAdapter);
For more information and customisations:
https://github.com/dvdciri/MultiChoiceRecyclerView
You can follow this:
– Data (String name, boolean selected)
– Adapter with itemClickListener
– Activity or fragment
– activity_main (recyclerView)
– list_item (TextView, CheckBox)
Data
public class MultipleData {
private String mTitle;
private boolean mBoolean;
public MultipleData(String title, boolean mBoolean) {
this.mTitle = title;
this.mBoolean = mBoolean;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public boolean isBoolean() {
return mBoolean;
}
public void setBoolean(boolean mBoolean) {
this.mBoolean = mBoolean;
}
}
Your views activity_main.xml (recyclerView)
<FrameLayout 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"
tools:context="com.thedeveloperworldisyours.fullrecycleview.multiple.MultipleFragment">
<android.support.v7.widget.RecyclerView
android:id="#+id/multiple_fragment_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
and list_item.xml (TextView, CheckBox)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/multiple_list_item_text"
android:layout_width="match_parent"
android:layout_height="90dp"
android:text="#string/app_name"
android:typeface="monospace"
android:layout_toLeftOf="#+id/multiple_list_item_check_button"
android:gravity="center"
android:textSize="#dimen/multiple_list_item_size_rock_stars"/>
<RadioButton
android:id="#+id/multiple_list_item_check_button"
android:layout_width="wrap_content"
android:layout_height="90dp"
android:layout_alignParentRight="true"
android:checked="false"
android:clickable="false"
android:focusable="false" />
</RelativeLayout>
Adapter with ClickListener
public class MultipleRecyclerViewAdapter extends RecyclerView
.Adapter<MultipleRecyclerViewAdapter
.DataObjectHolder> {
private List<MultipleData> mList;
private static MultipleClickListener sClickListener;
MultipleRecyclerViewAdapter(List<MultipleData> mList) {
this.mList = mList;
}
static class DataObjectHolder extends RecyclerView.ViewHolder
implements View
.OnClickListener {
TextView mTextView;
RadioButton mRadioButton;
DataObjectHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.multiple_list_item_text);
mRadioButton = (RadioButton) itemView.findViewById(R.id.multiple_list_item_check_button);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
sClickListener.onItemClick(getAdapterPosition(), v);
}
}
void changedData(int position) {
if (mList.get(position).isBoolean()) {
mList.get(position).setBoolean(false);
} else {
mList.get(position).setBoolean(true);
}
notifyDataSetChanged();
}
void setOnItemClickListener(MultipleClickListener myClickListener) {
this.sClickListener = myClickListener;
}
#Override
public DataObjectHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.multiple_list_item, parent, false);
DataObjectHolder dataObjectHolder = new DataObjectHolder(view);
return dataObjectHolder;
}
#Override
public void onBindViewHolder(DataObjectHolder holder, int position) {
holder.mTextView.setText(mList.get(position).getTitle());
holder.mRadioButton.setChecked(mList.get(position).isBoolean());
}
#Override
public int getItemCount() {
return mList.size();
}
interface MultipleClickListener {
void onItemClick(int position, View v);
}
}
Activity or fragment
public class MultipleFragment extends Fragment implements MultipleRecyclerViewAdapter.MultipleClickListener{
MultipleRecyclerViewAdapter mAdapter;
public MultipleFragment() {
// Required empty public constructor
}
public static MultipleFragment newInstance() {
return new MultipleFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.multiple_fragment, container, false);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.multiple_fragment_recycler_view);
MultipleData hendrix = new MultipleData("Jimi Hendrix", false);
MultipleData bowie = new MultipleData("David Bowie", false);
MultipleData morrison = new MultipleData("Jim Morrison", false);
MultipleData presley = new MultipleData("Elvis Presley", false);
MultipleData jagger = new MultipleData("Mick Jagger", false);
MultipleData cobain = new MultipleData("Kurt Cobain", false);
MultipleData dylan = new MultipleData("Bob Dylan", false);
MultipleData lennon = new MultipleData("John Lennon", false);
MultipleData mercury = new MultipleData("Freddie Mercury", false);
MultipleData elton = new MultipleData("Elton John", false);
MultipleData clapton = new MultipleData("Eric Clapton", false);
List<MultipleData> list = new ArrayList<>();
list.add(0, hendrix);
list.add(1, bowie);
list.add(2, morrison);
list.add(3, presley);
list.add(4, jagger);
list.add(5, cobain);
list.add(6, dylan);
list.add(7, lennon);
list.add(8, mercury);
list.add(9, elton);
list.add(10, clapton);
mAdapter = new MultipleRecyclerViewAdapter(list);
recyclerView.setAdapter(mAdapter);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
mAdapter.setOnItemClickListener(this);
return view;
}
#Override
public void onItemClick(int position, View v) {
mAdapter.changedData(position);
}
}
You can see this example in GitHub and this post for multiple choice, and this post for single choice Happy code!!!