RecyclerView and CardView implement onClick - java

I have a bunch of values that get pulled from mysql database and then are displayed in cardview using RecyclerView. This works great.
I want to now implement onClick on each item that is pulled, can anyone please point me in the right direction? I'm looking at being able to click on a card and have another view open with the "image", "name" and "publisher" values that are pulled from mysql using json, problem is I don't know how to pass these values onto a new activity, especially the values being pulled from mysql.
Movies.java
public class Movies extends AppCompatActivity implements RecyclerView.OnScrollChangeListener {
//Creating a List of superheroes
private List<SuperHero> listSuperHeroes;
//Creating Views
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
//Volley Request Queue
private RequestQueue requestQueue;
//The request counter to send ?page=1, ?page=2 requests
private int requestCount = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.movies);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//Initializing Views
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
layoutManager = new GridLayoutManager(this,2);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL_LIST));
recyclerView.setItemAnimator(new DefaultItemAnimator());
//Initializing our superheroes list
listSuperHeroes = new ArrayList<>();
requestQueue = Volley.newRequestQueue(this);
//Calling method to get data to fetch data
getData();
//Adding an scroll change listener to recyclerview
recyclerView.setOnScrollChangeListener(this);
//initializing our adapter
adapter = new CardAdapter(listSuperHeroes, this);
//Adding adapter to recyclerview
recyclerView.setAdapter(adapter);
}
//Add back button to go back
#Override
public void onBackPressed() {
super.onBackPressed();
overridePendingTransition(R.anim.activity_back_in, R.anim.activity_back_out);
}
public boolean onSupportNavigateUp(){
finish();
overridePendingTransition(R.anim.activity_back_in, R.anim.activity_back_out);
return true;
}
//Request to get json from server we are passing an integer here
//This integer will used to specify the page number for the request ?page = requestcount
//This method would return a JsonArrayRequest that will be added to the request queue
private JsonArrayRequest getDataFromServer(int requestCount) {
//Initializing ProgressBar
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar1);
//Displaying Progressbar
progressBar.setVisibility(View.VISIBLE);
setProgressBarIndeterminateVisibility(true);
//JsonArrayRequest of volley
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigMovies.DATA_URL + String.valueOf(requestCount),
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
//Calling method parseData to parse the json response
parseData(response);
//Hiding the progressbar
progressBar.setVisibility(View.GONE);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progressBar.setVisibility(View.GONE);
//If an error occurs that means end of the list has reached
Toast.makeText(Movies.this, "No More Items Available", Toast.LENGTH_SHORT).show();
}
});
//Returning the request
return jsonArrayRequest;
}
//This method will get data from the web api
private void getData() {
//Adding the method to the queue by calling the method getDataFromServer
requestQueue.add(getDataFromServer(requestCount));
//Incrementing the request counter
requestCount++;
}
//This method will parse json data
private void parseData(JSONArray array) {
for (int i = 0; i < array.length(); i++) {
//Creating the superhero object
SuperHero superHero = new SuperHero();
JSONObject json = null;
try {
//Getting json
json = array.getJSONObject(i);
//Adding data to the superhero object
superHero.setImageUrl(json.getString(ConfigMovies.TAG_IMAGE_URL));
superHero.setName(json.getString(ConfigMovies.TAG_NAME));
superHero.setPublisher(json.getString(ConfigMovies.TAG_PUBLISHER));
} catch (JSONException e) {
e.printStackTrace();
}
//Adding the superhero object to the list
listSuperHeroes.add(superHero);
}
//Notifying the adapter that data has been added or changed
adapter.notifyDataSetChanged();
}
//This method would check that the recyclerview scroll has reached the bottom or not
private boolean isLastItemDisplaying(RecyclerView recyclerView) {
if (recyclerView.getAdapter().getItemCount() != 0) {
int lastVisibleItemPosition = ((GridLayoutManager) recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
if (lastVisibleItemPosition != RecyclerView.NO_POSITION && lastVisibleItemPosition == recyclerView.getAdapter().getItemCount() - 1)
return true;
}
return false;
}
//Overriden method to detect scrolling
#Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
//Ifscrolled at last then
if (isLastItemDisplaying(recyclerView)) {
//Calling the method getdata again
getData();
}
}
}
CardAdapter.java
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
//Imageloader to load image
private ImageLoader imageLoader;
private Context context;
//List to store all superheroes
List<SuperHero> superHeroes;
//Constructor of this class
public CardAdapter(List<SuperHero> superHeroes, Context context){
super();
//Getting all superheroes
this.superHeroes = superHeroes;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.superheroes_list, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Getting the particular item from the list
SuperHero superHero = superHeroes.get(position);
//Loading image from url
imageLoader = CustomVolleyRequest.getInstance(context).getImageLoader();
imageLoader.get(superHero.getImageUrl(), ImageLoader.getImageListener(holder.imageView, R.drawable.ic_blank, android.R.drawable.ic_dialog_alert));
//Showing data on the views
holder.imageView.setImageUrl(superHero.getImageUrl(), imageLoader);
holder.textViewName.setText(superHero.getName());
holder.textViewPublisher.setText(superHero.getPublisher());
}
#Override
public int getItemCount() {
return superHeroes.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
//Views
public NetworkImageView imageView;
public TextView textViewName;
public TextView textViewPublisher;
//Initializing Views
public ViewHolder(View itemView) {
super(itemView);
imageView = (NetworkImageView) itemView.findViewById(R.id.imageViewHero);
textViewName = (TextView) itemView.findViewById(R.id.textViewName);
textViewPublisher = (TextView) itemView.findViewById(R.id.textViewPublisher);
}
}
}
Movies.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="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
<ProgressBar
android:id="#+id/progressBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</LinearLayout>
superheroes_list.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
android:layout_alignParentEnd="true"
android:layout_marginBottom="3dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/activity_horizontal_margin">
<com.android.volley.toolbox.NetworkImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:id="#+id/imageViewHero"
android:layout_gravity="center_horizontal" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableRow>
<TextView
android:text="Name"
android:paddingRight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/textViewName"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</TableRow>
<TableRow>
<TextView
android:text="Publisher"
android:paddingRight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/textViewPublisher"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
</TableLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>

Let the ViewHolder class implement View.OnClickListener, then move it into CardAdapter class.
Call setOnClickListener(this) just after calling super inside ViewHolder constructor like that:
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
imageView = (NetworkImageView) itemView.findViewById(R.id.imageViewHero);
textViewName = (TextView) itemView.findViewById(R.id.textViewName);
textViewPublisher = (TextView) itemView.findViewById(R.id.textViewPublisher);
}
#Override
public void onClick(View view) {
// here you can get your item by calling getAdapterPosition();
SuperHero superHero = superHeroes.get(getAdapterPosition());
}

Related

How to solve "java.lang.IllegalStateException: ArrayAdapter requires the resource ID to be a TextView" error?

The code is based by tinder tutorial:
public class arrayadapter extends ArrayAdapter<cards>
{
Context context;
public arrayadapter(Context context, int resource_id, List<cards> items)
{
super(context,resource_id,items);
}
public View getview(int position, View convertview, ViewGroup parent)
{
cards card_item = getItem(position);
if (convertview == null)
{
convertview = LayoutInflater.from(getContext()).inflate(R.layout.item,parent,false);
}
TextView user_name =(TextView) convertview.findViewById(R.id.user_name);
ImageView user_image =(ImageView) convertview.findViewById(R.id.image);
user_name.setText(card_item.getUser_name());
user_image.setImageResource(R.mipmap.ic_launcher); // change in the future with user pic
return convertview;
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="40sp"
android:paddingRight="40sp"
android:paddingTop="20sp"
android:paddingBottom="20sp"
android:outlineProvider="bounds"
android:clipToPadding="false"
>
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardCornerRadius="6dp"
android:elevation="2dp"
android:id="#+id/card_view"
>
<FrameLayout
android:layout_gravity="center"
android:layout_width="250dp"
android:layout_height="170dp"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/image">
</ImageView>
<TextView
android:id="#+id/user_name"
android:textSize="40sp"
android:textColor="#android:color/black"
android:gravity="center"
tools:text="hello"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
This are the swipe, arrayadapter classes and item xml. The data of the users are not important right now.
public class swipe_cards extends AppCompatActivity {
private cards cards_data[] ;
private arrayadapter arrayadapter;
private int i;
ListView listView;
List<cards>rowitems;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe_cards);
Bundle extras = getIntent().getExtras();
rowitems = new ArrayList<cards>();
//arrayadapter = new arrayadapter (this,R.layout.item,rowitems);
//context,YourCustomLayoutID,TextViewIDinYourLayout,ListData
arrayadapter = new arrayadapter(this,R.layout.item,rowitems);
// ArrayAdapter arrayAdapter = new ArrayAdapter(MainActivity.this,
// R.layout.layout_item_autocomplete, R.id.tvCustom, getResources().getStringArray(R.array.sweets));
SwipeFlingAdapterView flingContainer =(SwipeFlingAdapterView)findViewById(R.id.frame);
flingContainer.setAdapter(arrayadapter);
flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener() {
#Override
public void removeFirstObjectInAdapter() {
// this is the simplest way to delete an object from the Adapter (/AdapterView)
Log.d("LIST", "removed object!");
rowitems.remove(0);
arrayadapter.notifyDataSetChanged();
}
#Override
public void onLeftCardExit(Object dataObject) {
//Do something on the left!
//You also have access to the original object.
//If you want to use it just cast it (String) dataObject
Toast.makeText(swipe_cards.this, "Left!",Toast.LENGTH_SHORT).show();
}
#Override
public void onRightCardExit(Object dataObject) {
Toast.makeText(swipe_cards.this, "Right!",Toast.LENGTH_SHORT).show();
}
#Override
public void onAdapterAboutToEmpty(int itemsInAdapter) {
// Ask for more data here
//rowitems.add("XML ".concat(String.valueOf(i)));
arrayadapter.notifyDataSetChanged();
Log.d("LIST", "notified");
i++;
}
#Override
public void onScroll(float scrollProgressPercent) {
}
});
// Optionally add an OnItemClickListener
flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener() {
#Override
public void onItemClicked(int itemPosition, Object dataObject) {
Toast.makeText(swipe_cards.this, "Clicked!",Toast.LENGTH_SHORT).show();
}
});
if (extras != null)
{
ArrayList<String> users= extras.getStringArrayList("potential_users");
for (int counter = 0; counter < users.size(); counter++) {
String user = users.get(counter);
//String[] user_details= user.split(":");
String[] user_details = user.split(",");
String [] name_parmetrs= user_details[0].split(":");
String user_name= name_parmetrs[1];
cards card = new cards("222",user_name);
rowitems.add(card);
arrayadapter.notifyDataSetChanged();
}
}
}
You are creating an array adapter with the contructor where u are just giving 3 parameters- context, layout Id and the row-Items.
So for your constructor with only 3 parameters R.layout.item must be the id of a XML layout file containing only a TextView(the TextView can't be wrapped by another layout, like a LinearLayout, RelativeLayout etc!), something like this:
But in your case, you are using a complex layout So in that case you need to pass both layout id and Textview id in the constructor.
In case u need you don't have textViewId you can pass textViewId as 0.
like this
public arrayadapter(Context context, int resource_id, List<cards> items)
{
super(context,resource_id,0,items);
}
If u have a textview ResourceId you can pass the resourceid in place of 0
public arrayadapter(Context context, int resource_id,int textViewId, List<cards> items)
{
super(context,resource_id,textViewId,items);
}

Populate ImageView from BaseAdapter (Swipecards)

I am attempting to use the Swipecards library (https://github.com/Diolor/Swipecards) to build a tinder-esqe application. I am using a BaseAdapter to populate a layout with two text views and an image view that will be provided to the main SwipeFlingAdapterView. While both of the text fields are populated, I cannot get the image to appear on the cards. I have tried this implementation with both an ArrayAdapter and a BaseAdapter and the results are the same.
The activity layout (deal_page_layout)
<FrameLayout
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_height="match_parent"
android:layout_width="match_parent">
<com.lorentzos.flingswipe.SwipeFlingAdapterView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/swipe_fling_view"
app:rotation_degrees="10"
tools:context=".DealPage"
android:alpha="1.0"
app:max_visible="2"
app:min_adapter_stack="5"/>
</FrameLayout>
The layout being populated by the BaseAdapter (deal_card)
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/deal_card_image">
</ImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/deal_card_title"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_margin="15dp"
android:gravity="center"
android:textSize="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/deal_card_description"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_margin="15dp"
android:gravity="center"
android:textSize="20dp"/>
</RelativeLayout>
BaseAdapter class
public class DealBaseAdapter extends BaseAdapter {
private Context context;
private List<GrubbyDeal> dealList;
private LayoutInflater li;
public DealBaseAdapter(Context context, LayoutInflater li, ArrayList<GrubbyDeal> dealList){
this.context = context;
this.dealList = dealList;
this.li = li;
}
#Override
public int getCount(){
return dealList.size();
}
#Override
public Object getItem(int position){
return dealList.get(position);
}
#Override
public long getItemId(int position){
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
ViewHolder viewHolder;
//resuse a view if possible
if(convertView == null){
convertView = li.inflate(R.layout.deal_card,parent,false);
viewHolder = new ViewHolder();
viewHolder.img = (ImageView) convertView.findViewById(R.id.deal_card_image);
viewHolder.title = (TextView) convertView.findViewById(R.id.deal_card_title);
viewHolder.desc = (TextView) convertView.findViewById(R.id.deal_card_description);
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
GrubbyDeal curDeal = dealList.get(position);
viewHolder.img.setImageURI(curDeal.getImageUri());
viewHolder.title.setText(curDeal.getTitle());
viewHolder.desc.setText(curDeal.getDescription());
return convertView;
}
//view holder class to hold cached findViewByID results
private static class ViewHolder {
public ImageView img;
public TextView title;
public TextView desc;
}
And the main activity (DealPage)
public class DealPage extends Activity {
private ArrayList<GrubbyDeal> dealList;
private DealBaseAdapter dealAdapter;
SwipeFlingAdapterView flingContainer;
#Override
public void onCreate(Bundle sis){
super.onCreate(sis);
setContentView(R.layout.deal_page_layout);
//add some awesome cat deals to the adapter
dealList = new ArrayList<>();
for(int i=0; i < 5; i++){
GrubbyDeal tmp = new GrubbyDeal(i);
dealList.add(tmp);
}
//add another type of cat deal to the list
dealList.add(new GrubbyDeal());
dealAdapter = new DealBaseAdapter(this, getLayoutInflater(), dealList);
flingContainer = (SwipeFlingAdapterView) findViewById(R.id.swipe_fling_view);
flingContainer.setAdapter(dealAdapter);
flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener() {
#Override
public void removeFirstObjectInAdapter() {
// this is the simplest way to delete an object from the Adapter (/AdapterView)
Log.d("LIST", "removed object!");
GrubbyDeal popped = dealList.remove(0);
dealList.add(popped);
dealAdapter.notifyDataSetChanged();
}
#Override
public void onLeftCardExit(Object dataObject) {
makeToast(DealPage.this, "Left!");
}
#Override
public void onRightCardExit(Object dataObject) {
makeToast(DealPage.this, "Right!");
}
#Override
public void onAdapterAboutToEmpty(int itemsInAdapter) {
dealList.add(new GrubbyDeal());
dealAdapter.notifyDataSetChanged();
Log.d("LIST", "notified");
}
#Override
public void onScroll(float scrollProgressPercent) {
View view = flingContainer.getSelectedView();
}
});
flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener() {
#Override
public void onItemClicked(int itemPosition, Object dataObject) {
makeToast(DealPage.this, "Clicked!");
}
});
}
}
Am I missing something obvious? Is there some vastly superior library that I should be using? Thanks,
Ian
I would recommend using Picasso to load images into your imageview.
Picasso.with(context).load(imgurl).into(viewHolder.img);
The problem was formatting. I was attempting to use
Uri.parse("android.resource://com.thepackage.theapp/R.drawable.cat4.jpg");
but wasn't getting a valid Uri back. So instead I am using resource ids with picasso and the card works great!

Add items to bottom of Recycler View

Code of the illustration:
mLinearLayoutManager = new LinearLayoutManager(this);
mLinearLayoutManager.setReverseLayout(true);
mLinearLayoutManager.setStackFromEnd(true);
mMessageRecyclerView.setLayoutManager(mLinearLayoutManager);
See illustration here
How can I add new items (in my case, messages) to the bottom of Recycler View and still keep the "gravity" of the view to the top?
So, what works now is the following:
The gravity of the view is at the top. That's good! ✓
What doesn't work:
New messages are added to the top of the view. That's bad ×
I want them to be added at the bottom of the view (after the previous message) like so:
See here
Try removing these two lines or setting them false
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
setStackFromEnd will set the view to show the last element, the layout direction will remain the same whereas setReverseLayout will change the order of the elements added by the Adapter.
Try using this to move your RecyclerView and EditText up when keyboard appears
<activity name="YourActivity"
android:windowSoftInputMode="stateHidden|adjustResize">
//stateHidden -> keyboard is hidden when you first open the activity
//adjustResize -> this will adjust the layout resize option
...
</activity>
in AndroidManifest.xml.
To hook the RecyclerView at top
<android.support.v7.widget.RecyclerView
android:id="#+id/messageRecyclerViewRep"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="#+id/linearLayout3"
android:layout_marginLeft="36dp"
android:scrollbars="vertical" />
To put the recyclerView at bottom first and push it up as the keyboard pops up.
<LinearLayout
android:id="#+id/recyclerContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/linearLayout3"
android:layout_above="#+id/linearLayout"
android:gravity="bottom">
<android.support.v7.widget.RecyclerView
android:id="#+id/messageRecyclerViewRep"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="36dp"
android:scrollbars="vertical" />
</LinearLayout>
To scroll the recyclerView to bottom when keyboard pops up i.e. when the recycler view's layout is changed ( You can do the same thing on Edit Text active or focused or clicked or something like that. I've done it on recycler view's layout change. )
recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (bottom < oldBottom) {
recyclerView.postDelayed(new Runnable() {
#Override
public void run() {
recyclerView.smoothScrollToPosition(mAdapter.getItemCount());
}
}, 100);
}
}
});
setReverseLayout(true) this will reverse the item traversal & layout order.The first item will come to end not view or content.
setStackFromEnd(true) this will fill the recycler list content starting from the bottom of the view.
Need to setStackFromEnd(true) not setReverseLayout(true)
And in XML Recyclerview height should be match_parent
Below i have given working code.
activity xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="#+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add" />
<android.support.v7.widget.RecyclerView
android:id="#+id/rcList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="true" />
</LinearLayout>
list item xml layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:gravity="center_vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content" android:textSize="23sp"
android:layout_height="wrap_content" android:textColor="#4a4883"
android:text="Test Text" />
</FrameLayout>
Adapter class
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private static final String TAG = "CustomAdapter";
private ArrayList<String> mDataSet;
private int size = 0;
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView textView;
public ViewHolder(View v) {
super(v);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Element " + getAdapterPosition() + " clicked.");
}
});
textView = (TextView) v.findViewById(R.id.textView);
}
public TextView getTextView() {
return textView;
}
}
public CustomAdapter(ArrayList<String> dataSet) {
mDataSet = dataSet;
if (mDataSet != null && !mDataSet.isEmpty()) {
size = mDataSet.size();
}
}
public void refreshData(String add) {
if (!TextUtils.isEmpty(add)) {
mDataSet.add(add);
size = mDataSet.size();
notifyDataSetChanged();
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
// Create a new view.
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.list_item, viewGroup, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
Log.d(TAG, "Element " + position + " set.");
viewHolder.getTextView().setText(mDataSet.get(position));
}
#Override
public int getItemCount() {
return size;
}
}
Activity class
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
protected CustomAdapter mAdapter;
protected LinearLayoutManager mLayoutManager;
protected ArrayList<String> listString = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.rcList);
mLayoutManager = new LinearLayoutManager(this);
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
/**
*setStackFromEnd true will fill the content(list item) from the bottom of the view
*/
mLayoutManager.setStackFromEnd(true);
mLayoutManager.setReverseLayout(true);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
findViewById(R.id.btnAdd).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int temp = mAdapter.getItemCount() + 1;
mAdapter.refreshData("Test text " + temp);
mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount());
}
});
mAdapter = new CustomAdapter(listString);
mRecyclerView.setAdapter(mAdapter);
}
}
The simplest way to achieve this would be to load the elements into the Recyclerview in the reverse order to how they are entered in the Firebase Database.
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
Log.d(TAG, "Element " + position + " set.");
viewHolder.getTextView().setText(mDataSet.get(getItemCount() - 1 -position));
}
What this would do is that the item which is inserted last will get displayed at bottom since you are loading the items from top. No need for any change in any of the XMLs or any other code.
I had same issues with Recylerview not resizing itself when the keyboard pops up and therefore I resorted to this method.
All the best!!
I have implemented and here is my Implementation using FirebaseRecyclerView
you need to set this setStackFromEnd=true and setReverseLayout=true
my xml
Recycler View Holder
public class TestingFirebaseHolder extends RecyclerView.ViewHolder {
private TextView mTextView;
private TextView mTextView2;
public TestingFirebaseHolder(View itemView) {
super(itemView);
mTextView = itemView.findViewById(R.id.textViewTesting);
mTextView2 = itemView.findViewById(R.id.textViewTesting2);
}
public void setTextView(String text,String text2)
{
mTextView.setText(text);
mTextView2.setText(text2);
}
}
Testing Class
public class TestingUser {
public String UserName;
public String mUid;
public TestingUser() {
}
public TestingUser(String userName, String uid) {
UserName = userName;
mUid = uid;
}
}
Activity Code
private EditText mEditText;
private RecyclerView mRecyclerView;
private FirebaseRecyclerAdapter<TestingUser,TestingFirebaseHolder> mAdapter;
private FirebaseUser mUser;
private DatabaseReference mReference;
mEditText = findViewById(R.id.testingEditText);
mRecyclerView = findViewById(R.id.hello_rec);
mUser = FirebaseAuth.getInstance().getCurrentUser();
mReference = FirebaseDatabase.getInstance().getReference();
LinearLayoutManager ll = new LinearLayoutManager(this);
ll.setReverseLayout(true); // set this
ll.setStackFromEnd(true); // set this
mRecyclerView.setLayoutManager(ll);
Query query = mReference.child("Testing").child(mUser.getUid()).orderByValue();
mAdapter = new FirebaseRecyclerAdapter<TestingUser, TestingFirebaseHolder>(
TestingUser.class,R.layout.testing_recycler_layout,TestingFirebaseHolder.class,query
) {
#Override
protected void populateViewHolder(TestingFirebaseHolder viewHolder, TestingUser model, int position) {
viewHolder.setTextView(model.mUid,model.UserName);
}
};
mRecyclerView.setAdapter(mAdapter);
public void buttonClick(View view) {
if(!mEditText.getText().toString().isEmpty())
{
TestingUser user = new TestingUser("Salman",mEditText.getText().toString());
mReference.child("Testing").child(mUser.getUid()).push().setValue(user);
mEditText.setText("");
}
}
Result is
link
Try this, it works for me.
mLinearLayoutManager = new LinearLayoutManager(this);
mLinearLayoutManager.stackFromEnd(true)
mLinearLayoutManager.isSmoothScrollbarEnabled(true)
mMessageRecyclerView.setLayoutManager(mLinearLayoutManager);

how Do i register 81 textviews in android?

I am building a sudoku in android ,so how do i register all the textviews
for e.g :
button1=(Button)findViewByid(R.id.btn1)
Do i need to write 81 such statements to register every TextView
you can add the views in java code when app running.
you can write your textview's xml statement in an xml file alone, and then inflate it.
In this way, you don't need the view id, because you already have its reference.
grid.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
...
/>
MyActivity.java
ArrayList<TextView> list = new ArrayList<>();
for (int i = 0; i < 81; i++) {
TextView view = (TextView)LayoutInflater.from(ItemDragAndSwipeUseActivity.this).inflate(R.layout.grid, null);
list.add(view);
}
// then attach these views to the layout with addView()
you can use grid view with an adapter instead of text views
grid item
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="13sp"
android:text="#string/country_name"
android:textColor="#color/accent_color"
android:gravity="center"
android:paddingBottom="8dp"
android:paddingTop="8dp"
android:background="#color/color_primary_dark"/>
</RelativeLayout>
Adapter class
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolders> {
private List<ItemObject> itemList;
private Context context;
public RecyclerViewAdapter(Context context, List<ItemObject> itemList) {
this.itemList = itemList;
this.context = context;
}
#Override
public RecyclerViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, null);
RecyclerViewHolders rcv = new RecyclerViewHolders(layoutView);
return rcv;
}
#Override
public void onBindViewHolder(RecyclerViewHolders holder, int position) {
holder.textView.setText(itemList.get(position).getName());
}
#Override
public int getItemCount() {
return this.itemList.size();
}
public class RecyclerViewHolders extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView textView;
public RecyclerViewHolders(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
textView = (TextView)itemView.findViewById(R.id.textView);
}
#Override
public void onClick(View view) {
Toast.makeText(view.getContext(), "Clicked Position = " + getPosition(), Toast.LENGTH_SHORT).show();
}
}
}
Activity class
public class MainActivity extends ActionBarActivity {
private GridLayoutManager lLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle(null);
Toolbar topToolBar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(topToolBar);
topToolBar.setLogo(R.drawable.logo);
topToolBar.setLogoDescription(getResources().getString(R.string.logo_desc));
List<ItemObject> rowListItem = getAllItemList();
lLayout = new GridLayoutManager(MainActivity.this, 4);
RecyclerView rView = (RecyclerView)findViewById(R.id.recycler_view);
rView.setHasFixedSize(true);
rView.setLayoutManager(lLayout);
RecyclerViewAdapter rcAdapter = new RecyclerViewAdapter(MainActivity.this, rowListItem);
rView.setAdapter(rcAdapter);
}
private List<ItemObject> getAllItemList(){
List<ItemObject> allItems = new ArrayList<ItemObject>();
allItems.add(new ItemObject("1");
allItems.add(new ItemObject("2");
allItems.add(new ItemObject("3");
return allItems;
}
}
You don't have to use IDs for this. You can just create a View (Container) in XML and fill it using a for loop completely without using IDs. You can access them afterwards via their index in the Container.
I hope this helped.

Why are my "posts" loading in different sizes in android recyclerview?

Okay, this is how my recyclerview is showing my "posts". Can anyone tell me why? I will post source code as well. I have tried changing some of the code with no success. Also, when I scroll through my RecyclerView, some of them resize to smaller or larger sizes. Any and all help is appreciated!
fragment_home.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff" />
</LinearLayout>
list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/listItemLayout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:id="#+id/yesButton"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:background="#00FF00" />
<ImageButton
android:id="#+id/noButton"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_weight="1"
android:background="#FF0000" />
</LinearLayout>
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/image_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/placeholder" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:background="#509f9f9f"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="8"
android:orientation="horizontal">
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/thumbnail"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="fitXY"
android:src="#drawable/placeholder" />
<TextView
android:id="#+id/pUsername"
android:layout_marginLeft="5dp"
android:layout_marginStart="5dp"
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="username" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<ImageButton
android:id="#+id/postMenu"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#000"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
LruBitmapCache.java:
public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageCache {
public LruBitmapCache(int maxSize) {
super(maxSize);
}
public LruBitmapCache(Context context) {
this(getCacheSize(context));
}
#Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
#Override
public Bitmap getBitmap(String url) {
return get(url);
}
#Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
public static int getCacheSize(Context context) {
final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
final int screenWidth = displayMetrics.widthPixels;
final int screenHeight = displayMetrics.heightPixels;
final int screenBytes = screenWidth * screenHeight * 4;
return screenBytes * 3;
}
}
MyRecyclerAdapter.java:
public class MyRecyclerAdapter extends RecyclerView.Adapter<ListRowViewHolder> {
private List<ListItems> listItemsList;
private Context mContext;
private ImageLoader mImageLoader;
private int focusedItem = 0;
public MyRecyclerAdapter(Context context, List<ListItems> listItemsList) {
this.mContext = context;
this.listItemsList = listItemsList;
}
#Override
public ListRowViewHolder onCreateViewHolder(final ViewGroup viewGroup, int position) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, null);
ListRowViewHolder holder = new ListRowViewHolder(v);
return holder;
}
#Override
public void onBindViewHolder(final ListRowViewHolder listRowViewHolder, int position) {
ListItems listItems = listItemsList.get(position);
listRowViewHolder.itemView.setSelected(focusedItem == position);
listRowViewHolder.getLayoutPosition();
mImageLoader = MySingleton.getInstance(mContext).getImageLoader();
listRowViewHolder.thumbnail.setImageUrl(listItems.getProfilePicture(), mImageLoader);
listRowViewHolder.thumbnail.setDefaultImageResId(R.drawable.placeholder);
listRowViewHolder.image_1.setImageUrl(listItems.getImage_1(), mImageLoader);
listRowViewHolder.image_1.setDefaultImageResId(R.drawable.placeholder);
listRowViewHolder.username.setText(Html.fromHtml(listItems.getUsername()));
}
public void clearAdapter() {
listItemsList.clear();
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return (null != listItemsList ? listItemsList.size() : 0);
}
}
MySingleton.java:
public class MySingleton {
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static Context mContext;
private MySingleton(Context context) {
mContext = context;
mRequestQueue = getRequestQueue();
mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(LruBitmapCache.getCacheSize(mContext)));
}
public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}
ListRowViewHolder.java:
public class ListRowViewHolder extends RecyclerView.ViewHolder {
protected NetworkImageView thumbnail;
protected NetworkImageView image_1;
protected ImageButton yes;
protected ImageButton no;
protected TextView username;
protected LinearLayout recLayout;
public ListRowViewHolder(View view) {
super(view);
this.thumbnail = (NetworkImageView) view.findViewById(R.id.thumbnail);
this.image_1 = (NetworkImageView) view.findViewById(R.id.image_1);
this.yes = (ImageButton) view.findViewById(R.id.yesButton);
this.no = (ImageButton) view.findViewById(R.id.noButton);
this.username = (TextView) view.findViewById(R.id.pUsername);
this.recLayout = (LinearLayout) view.findViewById(R.id.listItemLayout);
view.setClickable(true);
}
}
FragmentHome.java:
public class FragmentHome extends Fragment {
private final String postsUrl = "http://www.example.com/fetch_posts.php";
private ProgressDialog progressDialog;
private static final String TAG = "RecyclerViewExample";
private List<ListItems> listItemsList = new ArrayList<>();
private RecyclerView mRecyclerView;
private MyRecyclerAdapter adapter;
public FragmentHome() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (container == null) {
return null;
}
View view = inflater.inflate(R.layout.fragment_home, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
mRecyclerView.addItemDecoration(
new HorizontalDividerItemDecoration.Builder(getActivity())
.color(Color.BLACK)
.build());
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(linearLayoutManager);
updateFeed();
return view;
}
public void updateFeed() {
showPD();
adapter = new MyRecyclerAdapter(getActivity(), listItemsList);
mRecyclerView.setAdapter(adapter);
RequestQueue request = Volley.newRequestQueue(getActivity());
adapter.clearAdapter();
JsonArrayRequest req = new JsonArrayRequest(postsUrl, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
try {
for (int i = 0; i < response.length(); i++) {
JSONObject post = (JSONObject) response.get(i);
ListItems item = new ListItems();
item.setImage_1(post.getString("image_1"));
item.setUsername(post.getString("username"));
item.setProfilePicture(post.getString("image_1"));
listItemsList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getActivity(), "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
adapter.notifyDataSetChanged();
hidePD();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
hidePD();
Toast.makeText(getActivity(), "Volley Error: " + error.getMessage(), Toast.LENGTH_LONG).show();
}
});
request.add(req);
}
private void showPD() {
if (progressDialog == null) {
progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(false);
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.show();
}
}
private void hidePD() {
if (progressDialog != null) {
progressDialog.dismiss();
progressDialog = null;
}
}
#Override
public void onDestroy() {
super.onDestroy();
hidePD();
}
}
Regarding the question "Also, when I scroll through my RecyclerView, some of them resize to smaller or larger sizes." :
As the name says 'Recycler', it reuses the ViewHolder objects. When you scroll down/up and when the view (holder) goes off the screen, the view object wont get destroyed but it will be used again (recycled) to hold/represent another data set that is becoming visible.
If data set at the new position that is becoming visible does not have data (may be null or empty etc) which in your case is profile_pic/thumbnail, the RecyclerView will use the the data of the recycled holder which is used to represent this position. That is why when you have many data sets than that screen can hold and when you scroll up/down, you see that everytime you scroll a view (make it visible and invisible), it will show different data depending on the (recycled)holder it uses at the moment. If your profile pics are different than just cat pic for every view, then you can witness this effect clearly.
What you've to do is that before you set the data (image, text etc) to a view, you can better reset it first. If it is image you can clear/reset as suggested here https://stackoverflow.com/a/8243184/3209739. Or you can have placeholder image or make it transparent whatever. Then this problem should not occur.
I think for same reason, it shows the different sized images (thumb and profile pic).
Try resetting the views before you set to your actual data. Always better to follow this when RecyclerView is used.
Why do you want to have your own caching code ? Why can not you use Picasso image loader, Universal Image Loader or something that suits your requirement. Take a look here to know the different image loaders Picasso v/s Imageloader v/s Fresco vs Glide.
You're not properly inflating your View in onCreateViewHolder() Instead of
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, null);
you should use
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, viewGroup, false);
See this answer for more details on the different LayoutInflater.inflate() methods.

Categories

Resources