I'm trying the two new features in android L version,
RecyclerView
CardView
Well the RecyclerView got working fine for me.But when I tried to execute the CardView.It throws an error and I was not able to find whats the error is!
MainActivity.java
public class MainActivity extends Activity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] myDataset ={"Uday","Harihar","chetan","ravi","harish","Rahul","satish","vikaram","ravikiran","harish2"};
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
// improve performance if you know that changes in content
// do not change the size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example)
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
}
MyAdapter.java
package com.hrh.material;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private String[] mDataset;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView mTextView;
public ViewHolder(View v) {
super(v);
mTextView = (TextView)v.findViewById(R.id.text);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(String[] myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_card_view, parent, false);
// set the view's size, margins, paddings and layout parameters
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
holder.mTextView.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataset.length;
}
}
activity_card_view.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
>
<android.support.v7.widget.CardView
android:id="#+id/cardview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:elevation="100dp"
card_view:cardCornerRadius="8dp"
>
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.v7.widget.CardView>
</RelativeLayout>
in the layout it shows that "Resource id 0x7f040001 is not of type STYLE (instead anim)".
I resolve the issue following this steps:
Removing the android-support-v7-appcompat, and cardview libs projects from my IDE (Eclipse in my case).
Update Android SDK Tools and Android Support Library from Android SDK Manager.
Restart your IDE (Eclipse).
Import the android-support-v7-appcompat, and cardview libs projects.
And make sure you added xmlns:card_view at the top of your your xml file:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp">
And thats it , hope it helps.
i am also facing same error,i found solution for this just remove two packages from sdk and install again.They are Extras->android support repository and android support library
Related
I'm trying to build a word-to-word RTL language ebook application. The data for the ebook is stored in an Sqlite database. After vigorous searching I found Flexbox layout suitable to my need in order to display my data in my required format. The following link helped me out: Android GridLayout with dynamic number of columns per row But the issue is that if the data passed in the view is large, then partial data is being displayed. If the data passed is small, then i have no issues at all.
Here is the adapter code:
public class VerseAdapter extends RecyclerView.Adapter<VerseAdapter.ViewHolder> {
private List<verseItem> items;
private Context context;
wordsAdapter sAdapter;
GridLayoutManager layoutManager;
public VerseAdapter(List<verseItem> items, Context context) {
this.items = items;
this.context = context;
}
// This method is used to attach
// custom layout to the recycler view
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View vw = LayoutInflater.from(parent.getContext()).inflate(R.layout.verse_row, parent, false);
return new ViewHolder(vw);
}
// This method is used to set the action
// to the widgets of our custom layout.
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
verseItem item = items.get(position);
ArrayList<wordsModel> models = new ArrayList<>(item.getWordsModelList());
String ayahnum = "" + item.getAyah();
holder.ayah.setText(ayahnum);
holder.verses_telugu.setText(item.getVerses_telugu());
// FlexboxLayoutManager code:
FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(context);
layoutManager.setFlexDirection(FlexDirection.ROW_REVERSE);
layoutManager.setJustifyContent(JustifyContent.FLEX_START);
ViewHolder.wordsrecyclerView.setLayoutManager(layoutManager);
sAdapter = new wordsAdapter(models);
ViewHolder.wordsrecyclerView.setAdapter(sAdapter);
sAdapter.notifyItemChanged(position);
holder.setIsRecyclable(false);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView ayah;
TextView verses_telugu;
public static RecyclerView wordsrecyclerView;
public ViewHolder(View itemView) {
super(itemView);
ayah = itemView.findViewById(R.id.ayah);
verses_telugu = itemView.findViewById(R.id.telugu_line);
wordsrecyclerView = itemView.findViewById(R.id.words_RV_id);
}
}
}
Here is my layout file:
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/ayah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_margin="5dp"
android:textAlignment="viewStart"
android:textColor="#27A82C"
android:textSize="18sp"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/words_RV_id"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/telugu_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_margin="5dp"
android:textAlignment="textStart"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
This is how the final result show actually look like:
This is how my app looks like:
Now if you notice from the screenshots, the data that i'm trying to display is same. But in my app, not all words are being displayed as you can notice.
Another thing i have noticed is for larger data if the screen orientation is vertical the maximum lines i can see is 10 and if it is horizontal i can see 6 lines at max. These number of lines are fixed for all the places where the data is large. If the data is smaller it is displayed in the exact number of lines required and as mentioned earlier I have no issues at all.
Hoping someone helps me out soon. Thanks in advance. (:
I have a root recyclerview and each item is populated with this layout:
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="#+id/headerText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/accent_gradient"
android:ellipsize="end"
android:maxLines="1"
android:padding="8dp"
android:paddingStart="16dp"
android:text="My original"
android:textColor="#color/colorWhite"
android:textSize="14sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rootRecycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
/>
</LinearLayout>
As you can see, there is another recylcerview within each item. I wanted to achieve the effect of sectioned recyclerview with headers. (So Header > List Header > List)
Now each recyclerview is populated with this layout view:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_toStartOf="#id/relativeLayout3"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:id="#+id/foodName_fv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:text="Food name"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#color/colorBlack"
android:textSize="18sp"
android:transitionName="Food_Name"/>
<TextView
android:layout_below="#id/foodName_fv"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:id="#+id/foodGrams_fv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:text="Grams"
android:textColor="#color/colorLightGrey"
android:textSize="15sp" />
<LinearLayout
android:id="#+id/relativeLayout3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:orientation="vertical"
android:layout_alignParentEnd="true"
>
<TextView
android:id="#+id/foodCalories_fv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Calories"
android:textColor="#color/colorBlack"
android:textSize="18sp"
android:transitionName="Food_Cal"/>
<TextView
android:layout_gravity="center"
android:id="#+id/calText_fv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingBottom="8dp"
android:text="#string/calText_fv"
android:textColor="#color/colorLightGrey"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>
This is a fairly simple layout but for some odd reason the child recyclerview takes soo much time to inflate these rows. I did some testings and it took (on average) 1200 ms to load 300 rows!
Now the weirdest thing is that before this code i had a plain listview (without any sections and headers, just a big list) and it loaded all these rows very fast. I have'nt changed nothing but this code (Converting it from listview with an adapter to recyclerview with an adapter) so it looks pretty strange to me, but i dont know i might be missing something here.
This is the onCreateViewHolder method:
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.food_view, parent, false);
return new ViewHolder(view);
}
In conclusion the child recyclerview takes too much time to do this work. And yes I am aware i can do "Lazy loading" but I want to figure out why the hell is it so slow?
EDIT 1:
Tried implementing it in a fresh new project, thought something with the broke somehow, but its still gave same results, also tried on my actual phone and not an emulator and still slow. I really want to figure out this one already because it seems very illogical.
EDIT 2:
Posting the adapters code for hamza khan:
Code for the root recyclerview:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class SelectFoodRootRecyclerAdapter extends RecyclerView.Adapter<SelectFoodRootRecyclerAdapter.ViewHolder> {
private static final String TAG = "SelectFoodRootRecyclerAdapter";
private Context mContext;
private ArrayList<SectionedFoodGroup> items;
private ArrayList<SelectFoodChildRecyclerAdapter> adapters; //For filter use outside this class
RecyclerView.RecycledViewPool recycledViewPool;
public SelectFoodRootRecyclerAdapter(Context mContext) {
this.mContext = mContext;
items = new ArrayList<>();
adapters = new ArrayList<>();
recycledViewPool = new RecyclerView.RecycledViewPool();
SectionedFoodGroup section1 = new SectionedFoodGroup(mContext.getString(R.string.myFoods),
FoodsDBHelper.getAllFoodRows(Food.DBType.USER_CREATED_FOODS_DB.ordinal()));
SectionedFoodGroup section2 = new SectionedFoodGroup(mContext.getString(R.string.foods),
FoodsDBHelper.getAllFoodRows(Food.DBType.REGULAR_FOOD_DB.ordinal()));
addSection(section1);
addSection(section2);
}
private void addSection(SectionedFoodGroup sectionedFoodGroup){
if(sectionedFoodGroup.getFoods().size() > 0){
items.add(sectionedFoodGroup);
adapters.add(new SelectFoodChildRecyclerAdapter(mContext, sectionedFoodGroup.getFoods()));
}
}
public ArrayList<SelectFoodChildRecyclerAdapter> getAdapters(){
return adapters;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_sfa_viewholder, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
SectionedFoodGroup sectionedFoodGroup = items.get(position);
holder.headerText.setText(sectionedFoodGroup.getHeaderName());
holder.foodsRecycler.setAdapter(adapters.get(position));
holder.foodsRecycler.setRecycledViewPool(recycledViewPool);
}
#Override
public int getItemCount() {
return items != null ? items.size() : 0;
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView headerText;
RecyclerView foodsRecycler;
public ViewHolder(#NonNull View itemView) {
super(itemView);
headerText = itemView.findViewById(R.id.headerText);
foodsRecycler = itemView.findViewById(R.id.rootRecycler);
}
}
}
Code for the child recyclerview (the one containing all the actual rows):
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import java.text.DecimalFormat;
import java.util.ArrayList;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class SelectFoodChildRecyclerAdapter extends RecyclerView.Adapter<SelectFoodChildRecyclerAdapter.ViewHolder>{
private static final String TAG = "SelectFoodChildRecyclerAdapter";
private Context mContext;
private ArrayList<Food> original;
private DecimalFormat decimalFormat;
public SelectFoodChildRecyclerAdapter(Context mContext, ArrayList<Food> foods) {
this.mContext = mContext;
this.original = foods;
decimalFormat = new DecimalFormat("#.0");
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.food_view, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int foodPos) {
Food currFood = original.get(foodPos);
holder.foodName.setText(currFood.getName());
float grams = 100;
if(currFood.getAmount() != 0) grams = (float)currFood.getAmount();
int roundedGrams = (int)Math.round(grams);
holder.foodGrams.setText(roundedGrams +" "+ mContext.getResources().getString(R.string.gramsWord));
float caloriesToShow = (float)currFood.getCalories();
holder.foodCalories.setText(decimalFormat.format(caloriesToShow));
}
#Override
public int getItemCount() {
return original != null ? original.size() : 0;
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView foodName;
TextView foodGrams;
TextView foodCalories;
public ViewHolder(View itemView) {
super(itemView);
foodName = itemView.findViewById(R.id.foodName_fv);
foodGrams = itemView.findViewById(R.id.foodGrams_fv);
foodCalories = itemView.findViewById(R.id.foodCalories_fv);
}
}
}
The calling activity onCreate method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_food);
foodsRecyclerView = findViewById(R.id.rootRecycler);
selectFoodRootRecyclerAdapter = new SelectFoodRootRecyclerAdapter(this);
foodsRecyclerView.setAdapter(selectFoodRootRecyclerAdapter);
}
Again, as you can see all the code is fairly simple..
EDIT 3:
Ok so i've narrowed it down even more. I tried to do just one big recyclerview of the second layout and it worked fast. SOOO the problem must be with the first layout/the root recyclerview adapter code. but everything seems fine with it...
I really don't know what am I missing here!! Thanks for any kind of help!
Thanks!
Well, because no one was able to answer my question and I've found my answer then ill share it with other people who might look at this in the future and think, wow this is exactly what I need.
So.. It turns out using a RecyclerView within RecyclerView is a big no no. thats because the onCreateViewHolder method gets called as many times as your items array size, and thats very heavy, especially if you have a large list. (I think its the same as RecyclerView within a ScrollView) - So try to avoid using this type of implementation.
So what can you do?
Option 1 - Create a multi view RecylcerView adapter. that means that you have one adapter and it can handle multiple view types (perfect for what i wanted. 1 view type is a header and the second view type is another layout to act as my main row).
You can look it up in google to find good results on how to implement it but the main
So declare these variables:
private int VIEW_TYPE_HEADER = 0;
private int VIEW_TYPE_MAIN_ROW = 1;
Next override the next method, and what this basically does it gives each row a special int which we then can compare in onCreateViewHolder and decide which layout we want to inflate (e.g. If its going to be a header or a main row)
#Override
public int getItemViewType(int itemPos) {
if(items.get(itemPos) instanceof String){
return VIEW_TYPE_HEADER;
}
return VIEW_TYPE_MAIN_ROW;
}
On the onCreateViewHolder we can test to see what type of row we are dealing with and inflate accordingly.
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_HEADER){
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header)_layout, parent, false);
return new HeaderViewHolder(view);
}
//Else a regular row.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_row, parent, false);
return new MainViewHolder(view);
}
And of course make a separate view holder for each type.
Option 2 - Because I need only 2-3 sections, what i could also do is just "hardcode" it like this:
Create a TextView to be the header and below it a RecyclerView AND again 2-3 times. this approach is obviously less flexible but it works if you want some small.
Hope this'll help someone one day.
Here is what I am trying to do:
What is the simplest way to create rows that scroll together and are composed of variable sized clickable Views with the same height on Android
Basically create variable width columns that have the same width in every row. Also need to add, delete and add listeners. Seems like a fairly simple task, but I am finding Android's GUI library a lot harder to figure out than Java's and WPF's GUI library.
Here is my RecyclerView:
public class MainActivity extends AppCompatActivity {
private RecyclerView ampRecyclerView;
private RecyclerView.Adapter ampAdapter;
private RecyclerView.LayoutManager ampLayoutManager;
List<FunctionView> myDataset = new ArrayList<FunctionView>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpRecyclerView();
}
private void setUpRecyclerView() {
LinearLayout linearLayout = findViewById(R.id.main_ll);
linearLayout.setWillNotDraw(false);
ampRecyclerView = (RecyclerView) findViewById(R.id.AmpRecyclerView);
// use a linear layout manager
ampLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
ampRecyclerView.setLayoutManager(ampLayoutManager);
myDataset.add(new FunctionView(this));
myDataset.add(new FunctionView(this));
myDataset.add(new FunctionView(this));
// specify an adapter
ampAdapter = new MainActivityAdapter(myDataset, 1);
ampRecyclerView.setAdapter(ampAdapter);
}
}
My adapter
class MainActivityAdapter extends RecyclerView.Adapter<MainActivityAdapter.FunctionViewHolder> {
private List<FunctionView> views = new ArrayList<FunctionView>();
private List<LinearLayout> llViews = new ArrayList<>();
private int rows;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class FunctionViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public LinearLayout linearLayout;
public FunctionViewHolder(LinearLayout v) {
super(v);
linearLayout = v;
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MainActivityAdapter(List<FunctionView> myDataset, int rows) {
views = myDataset;
this.rows = rows;
}
// Create new views (invoked by the layout manager)
#Override
public MainActivityAdapter.FunctionViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
LinearLayout linearLayout = (LinearLayout) LayoutInflater.from(parent.getContext())
.inflate(R.layout.function_holder, parent, false);
llViews.add(linearLayout);
MainActivityAdapter.FunctionViewHolder vh = new MainActivityAdapter.FunctionViewHolder(linearLayout);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(MainActivityAdapter.FunctionViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
int width = 0;
for(FunctionView fv : views){
holder.linearLayout.addView(fv);
width += fv.getWidth();
}
holder.linearLayout.setMinimumWidth(width);
//TODO set the data
// holder.functionView = views.get(position);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return rows;
}
I know there are glaring design flaws. I am trying to get the scrolling working first, because every layout I try doesn't work how I'd like.
Here is the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_ll"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/AmpRecyclerView"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
and the holder:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:isScrollContainer="true"
android:nestedScrollingEnabled="true"
>
</LinearLayout>
as you said there are glaring design flaws, but you need to change the android:layout_height to wrap_content and android:layout_width to match_Parent.
if your item's hight is match_parent then your inner layout's hight becomes the recyclerview's hight then there is no room for other items so there will be no scrolling.
also, put something like a textView in it to be able to see the items.
another note, the name is supposed to be item not holder. holder is related to ViewHolder which is a totally different thing. you can name it according to your activity for example if Your activity name is MainActivity so your activity layout is activity_main, then you can call the inner layouts item_main
I recommend watching a tutorial on youtube or read an article from medium or anywhere (you can simply just google android recyclerview example) to learn the basics.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="#+id/txt_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SAMPLE"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:textSize="30sp"
/>
</LinearLayout>
I've tried creating a RecyclerView which displays the songs I have on my phone from a pre-populated ArrayList. Here is my code for my activity:
public class HomeActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private RecyclerView songRecyclerView;
private RecyclerView.Adapter songRecyclerAdapter;
private RecyclerView.LayoutManager recyclerLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//get the songs list for the adapter
ArrayList<Audio> songList;
StorageUtils storageUtils = new StorageUtils(getApplicationContext());
songList = storageUtils.loadAudio();
//Recycler view setup for songs display
songRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
songRecyclerView.setHasFixedSize(true);
recyclerLayoutManager = new LinearLayoutManager(this);
songRecyclerView.setLayoutManager(recyclerLayoutManager);
songRecyclerAdapter = new SongAdapter(songList);
songRecyclerView.setAdapter(songRecyclerAdapter);
}
The Audio class has the getTitle() and getArtist() methods, which do work. The loud audio() also works so Songlist definitely has elements in it.
Here is the xml of the recyclerview item:
<?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"
android:id="#+id/recycler_item"
android:layout_width="match_parent"
android:layout_height="72dp"
android:visibility="visible">
<TextView
android:id="#+id/recycler_item_songName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="song name"
android:textColor="#color/textPrimary"
android:textSize="16sp"
android:textStyle="normal"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/recycler_item_artistName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="song artist"
android:textColor="#color/textSecondary"
android:textSize="16sp"
android:textStyle="normal"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/recycler_item_songName" />
</android.support.constraint.ConstraintLayout>
Here is my implementation of the Adapter:
package com.ecebuc.gesmediaplayer;
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 java.util.ArrayList;
public class SongAdapter extends RecyclerView.Adapter<SongAdapter.ViewHolder> {
// The dataset
private ArrayList<Audio> songList;
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView recyclerTitleView, recyclerArtistView;
public ViewHolder(View itemView) {
super(itemView);
this.recyclerTitleView = (TextView) itemView.findViewById(R.id.recycler_item_songName);
this.recyclerArtistView = (TextView) itemView.findViewById(R.id.recycler_item_artistName);
}
}
// Constructor
public SongAdapter(ArrayList<Audio> songList){
this.songList = songList;
}
#Override
public SongAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View listItemView = layoutInflater.inflate(R.layout.song_list_item, parent, false);
ViewHolder viewHolder = new ViewHolder(listItemView);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Audio currentSong = songList.get(position);
holder.recyclerTitleView.setText(currentSong.getTitle());
holder.recyclerArtistView.setText(currentSong.getArtist());
Log.d("onBind: ", (String)holder.recyclerTitleView.getText() + (String)holder.recyclerArtistView.getText());
}
#Override
public int getItemCount() {
return songList.size();
}
}
The frustrating thing is that at my very first attempt at creating the whole recycleView, it did work and displayed the text. I tried adding an imageView as the cover of the songs to the layout of each item in the list, and the code to display that as well, and it wasn't working anymore. When tried to revert and have only the code for text, it stopped working altogether.
I am bashing my head over this because if I did make some small change somewhere, I don't know where it might be any more now. But I did try to recreate the class for the adapter and the layout file for the whole recycler functionality from scratch, and still not showing. The layout items have to be there because I see the shadow of the scroll.
Also, in the adapter's onBindViewHolder, that Log.d displays correctly each song title and artist. And it calls the newly created views' getText(). It's like the text was white. And no, the values of #color/text primary and textSecondary in the XML are #212121 and #424242 and were always like that (again, it did display the values the first time, and I haven't touched the colours).
I've looked for similar problems on StackOverflow and online, but I don't seem to have that kind of mistakes. I don't know what to do anymore. Heck, I'll even include the XML of the screen that has the actual recyclerView in it. At this point I don't know what could make those views invisible:
<?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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".HomeActivity"
tools:showIn="#layout/app_bar_home">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Finally, I thought of looking at the developer options on my phone and display layout outlines, and this is what I had...as if the two textViews are not being created, yet I was able to get their text content after I've set it, so how is that even possible? Thank you to whoever can help me, I'm just trying to learn here...
For future reference in case anyone has a similar problem, I managed to solve it by simply changing my constraint layout in the recycler view item XML, to linear layout (or I'd guess whatever type of layout other than constraint) and compiled.
It worked well, displaying everything correctly. Then changing the XML back to constraint layout like before, and everything was still working fine. At this point I'd say it will forever remain a mystery.
make some change in adapter constructor like below code..
public Context context;
// Constructor
public SongAdapter(Context context,ArrayList<Audio> songList){
this.context=context;
this.songList = songList;
}
then after main activity make adapter object like below ..
SongAdapter adapter;
and remove this line of code ..
private RecyclerView.Adapter songRecyclerAdapter;
and used set adapter like below code..
RecyclerView recyclerView;
SongAdapter songRecyclerAdapter;
private void setAdapter(){
recyclerView.setLayoutManager(new LinearLayoutManager(this));
if (songRecyclerAdapter==null) {
songRecyclerAdapter = new SongAdapter(this,songList);
recyclerView.setAdapter(songRecyclerAdapter);
songRecyclerAdapter.notifyDataSetChanged();
}
else{
songRecyclerAdapter.notifyDataSetChanged();
}
}
Image
--
I want to achieve something like this in above image
I have to loop through this json array to get all my datas;
the data contained in my json array are for example
{
'img' : http:\\.....
'name' : XYZ
'msg' : xyz
'time' : abc
}
//this is where I am tring to append everything
final LinearLayout rl = (LinearLayout)main.findViewById(R.id.mainL);
for (int i = 0; i < json.length(); i++) {
try {
JSONObject c = json.getJSONObject(i);
//here components must be created and added to view
}catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I just want to know the how do you programmatically style the views(textview,imageview etc) like in the above image.
Any Help will be appreciated
Ok, the image you are looking at is actually a ListView serving custom-made views.
How does that work?
You will need to subclass the BaseAdapter class. This subclass will contain the underlying data which in your case you are getting as a JSON-formatted reply from the web-server.
When the getView() of the BaseAdapter subclass is called, you can inflate a layout that contains an ImageView and TextViews to display the data onscreen.
The answer is just for future visitors, since the question was asked long day ago. At first, I will just redirect you to my GitHub page where I used RecyclerView to show data and Retrofit to call data. I used Volley also. Finally, let me show simple way to load data to recyclerview.
You need an extra class call it CustomAdapter.
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {
Context context;
private String countryList[];
private int imgList[];
//constructor
public CustomAdapter(Context context, String countryList[],int imgList[]) {
this.context = context;
this.countryList = countryList;
this.imgList=imgList;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
// inflate the item Layout
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.items, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(view); // pass the view to View Holder
return vh;
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder myHolder, final int position) {
myHolder.txtName.setText(countryList[position]);
myHolder.imgCountry.setImageResource(imgList[position]);
// implement setOnClickListener event on item view.
myHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// display a toast with person name on item click
Toast.makeText(context, countryList[position], Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return countryList.length;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView txtName;
ImageView imgCountry;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
// get the reference of item view's
txtName = itemView.findViewById(R.id.txt_name);
imgCountry = itemView.findViewById(R.id.img_flag);
}
}
}
And in the MainActivity, you have declare a LayoutManager for RecyclerView and have to call CustomAdapter to load data in RecyclerView.
String countryList[]={"Bangladesh","India","China","Australia","America","New Zealand","Portugal"};
int imgList[]={R.drawable.bd,R.drawable.india,R.drawable.china,R.drawable.australia,R.drawable.america,R.drawable.new_zealand,R.drawable.portugle};
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// get the reference of RecyclerView
recyclerView = findViewById(R.id.recycler_view);
// set a LinearLayoutManager with default vertical orientation
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
// set a LinearLayoutManager with default Horizontal orientation
// LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext(),LinearLayoutManager.HORIZONTAL,false);
recyclerView.setLayoutManager(linearLayoutManager);
// call the constructor of CustomAdapter to send the reference and data to Adapter
CustomAdapter customAdapter = new CustomAdapter(MainActivity.this,countryList, imgList);
recyclerView.setAdapter(customAdapter); // set the Adapter to RecyclerView
}
activity_main.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:orientation="vertical"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
items.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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="#+id/img_flag"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="5dp"
app:srcCompat="#mipmap/ic_launcher" />
<TextView
android:id="#+id/txt_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center|left"
android:paddingLeft="10dp"
android:text="TextView"
android:textSize="24sp" />
</LinearLayout>
</LinearLayout>
Here's the github repository. If you are calling data from server then visit my Volley repo.