How can I set a header over a RecyclerView? - android

My Android app lists the audio files inside an specific folder by using a RecyclerView. However, I want to display at the top of that RecyclerView a header that indicates the current folder with a TextView, but I do not know how to do it.
Is there an easy way to achieve that?
This is my adapter code:
package vmc.songbook;
import android.content.Context;
import android.media.MediaMetadataRetriever;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.io.File;
import java.util.Date;
public class RecordingsAdapter extends RecyclerView.Adapter<RecordingsAdapter.ViewHolder> {
// Attributes
protected File[] files; // Files to include in the RecyclerView
protected LayoutInflater inflater; // This class creates the layout based on the XML file
/** Constructor */
public RecordingsAdapter(Context context, File[] files) {
this.files = files;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/** ViewHolder is needed to store the variables of each file */
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView file_name, file_duration, file_date;
public ViewHolder(View itemView) {
super(itemView);
file_name = (TextView) itemView.findViewById(R.id.file_name);
file_duration = (TextView) itemView.findViewById(R.id.file_duration);
file_date = (TextView) itemView.findViewById(R.id.file_date);
}
}
/** Inflating the ViewHolder based on the XML file*/
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = inflater.inflate(R.layout.file_element, null);
return new ViewHolder(v);
}
/** Maximum number of items */
#Override public int getItemCount() {
return files.length;
}
/** Customizing the ViewHolder */
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Setting the date
Date lastModDate = new Date(files[position].lastModified());
holder.file_date.setText(lastModDate.toString());
// Setting the audio duration
String duration = getDuration(files[position]);
holder.file_duration.setText(duration);
// Setting the audio name
holder.file_name.setText(files[position].getName());
}
}
Since I am usic a Basic Activity as Main Activity, my content_main.xml is the following:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
This is my current display:
And this is the view that what I want to achieve:
EDITED: If I create a simple TextView over the RecyclerView within a LinearLayout, the layout colocates itself over the action bar...

The simplest thing you can do is just add a text view above the recycler view :)
<?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"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TextView
android:id="#+id/title_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="title" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
In your activity class set that text view to the current folder path text.
title_text_view.setText("path/to/folder");

Using this code snippet works like a charm, with scroll of course:
https://github.com/cundong/HeaderAndFooterRecyclerView

Related

Howto Add Integers to a Listview With Custom Adapter

i have one list view with two text views inside it, one edit text that is in the same activity but not in the list view and two buttons one to add to the list view and the other to delete from it.
how to add integers to the first text view, the sum of all integers to the second one, and to be from a custom adapter.
thank you.
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:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<EditText
android:id="#+id/edit_ten"
android:hint="Score"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="#+id/btn_add"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Add"/>
<Button
android:id="#+id/btn_delete"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Undo"/>
</LinearLayout>
<ListView
android:id="#+id/list_sinhvien"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
item_layout.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="horizontal">
<LinearLayout
android:orientation="vertical"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text_ten"
android:textSize="20dp"
android:text="Score"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/text_sdt"
android:textSize="20dp"
android:text="Total"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
MainActivity.java
package com.example.addanddelete;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
ListView listSinhvien;
EditText editTen;
Button btnThem , btnSua;
ArrayList<Sinhvien> arraySinhvien;
CustomAdapter myadapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
anhxa();
arraySinhvien = new ArrayList<Sinhvien>();
myadapter = new CustomAdapter(this , R.layout.item_layout,arraySinhvien);
listSinhvien.setAdapter(myadapter);
btnSua.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final int count = myadapter.getCount();
myadapter.remove(myadapter.getItem(count -1));
myadapter.notifyDataSetChanged();
return;}});
}
private void anhxa(){
listSinhvien = (ListView)findViewById(R.id.list_sinhvien);
editTen = (EditText)findViewById(R.id.edit_ten);
btnThem = (Button)findViewById(R.id.btn_add);
btnSua = (Button)findViewById(R.id.btn_undo);
btnThem.setOnClickListener(this);
btnSua.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_add:
Toast.makeText(this, "clicked", Toast.LENGTH_SHORT).show();
String ten = editTen.getText().toString();
String sdt = editTen.getText().toString();
Sinhvien temp = new Sinhvien(R.mipmap.ic_launcher,ten , sdt);
arraySinhvien.add(temp);
myadapter.notifyDataSetChanged();
break;
}
}
}
CustomAdapter.java
package com.example.addanddelete;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
public class CustomAdapter extends ArrayAdapter {
Activity activity;
int layout;
ArrayList<Sinhvien> arrSinhVien;
public CustomAdapter(#NonNull Activity activity, int layout, #NonNull ArrayList<Sinhvien> arrSinhVien) {
super(activity, layout, arrSinhVien);
this.activity = activity;
this.layout = layout;
this.arrSinhVien = arrSinhVien;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
LayoutInflater layoutInflater = activity.getLayoutInflater();
convertView = layoutInflater.inflate(layout, null);
TextView ten = (TextView) convertView.findViewById(R.id.text_score);
TextView sdt = (TextView) convertView.findViewById(R.id.text_total);
ten.setText(arrSinhVien.get(position).getTenSinhvien());
sdt.setText(arrSinhVien.get(position).getSdtSinhvien());
return convertView;
}
}
Sinhvien.java
package com.example.addanddelete;
public class Sinhvien {
String tenSinhvien;
String sdtSinhvien;
public Sinhvien(String iclauncher,String ten, String sdt) {
}
public Sinhvien(int iclauncher,String tenSinhvien, String sdtSinhvien) {
this.tenSinhvien = tenSinhvien;
this.sdtSinhvien = sdtSinhvien;
}
public String getTenSinhvien() {
return tenSinhvien;
}
public void setTenSinhvien(String tenSinhvien) {
this.tenSinhvien = tenSinhvien;
}
public String getSdtSinhvien() {
return sdtSinhvien;
}
public void setSdtSinhvien(String sdtSinhvien) {
this.sdtSinhvien = sdtSinhvien;
}
}
The general behaviour/implementation that you've outlined in your question is very well documented. That said, I'd suggest considering utilising a RecyclerView with associated custom item view and adapter, as opposed to a ListView. There are a few reasons why I'd suggest this.
I did a little searching and found several examples that cover the general idea of your implementation. This example does a great job of illustrating how to achieve what you're seeking. The article begins by outlining some reasons to work with a RecyclerView over a ListView or GridView, then proceeds to give an in-depth run-down on how to implement a RecyclerView with custom adapter (and associated item view and item class).
At a glance, your implementation would require:
An Activity containing your RecyclerView, two Buttons (used for adding and deleting elements from the RecyclerView) and an EditText for taking user input.
A custom item View representing individual items of your RecyclerView list. This would contain the two TextView views (one for displaying the integer and the other for displaying the sum of all integers).
A custom item model Class to represent the data model for the above custom item View. This would hold an integer value and likely some logic for displaying the sum.
A custom RecyclerView adapter (which ties all of the above together). This will need to handle the task of binding data from your dataset (that grows and shrinks based on user input) to instances of your custom items that are to appear in the RecyclerView list. This adapter could also be used by your add and delete item buttons to modify the elements in the RecyclerView list.
The above is outlined in far greater depth in the link I provided earlier.
I sincerely hope that helps!

RecyclerView with CardView Items, notifyItemChanged and shadow problem

Is there any way to disable the CardView elevation animation from a recyclerview when an item is changed but to keep the original shadow and item animator?
I've tried to disable the CardView state animator android:stateListAnimator="#null" with no results.
Here's a way to reproduce the issue:
package com.w.cardviewrecyclerviewanim;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.CardView;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity {
RecyclerView items;
Adapter adapter = new Adapter();
GridLayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
items = findViewById(R.id.items);
layoutManager = new GridLayoutManager(this, 2, LinearLayoutManager.VERTICAL, false);
items.setLayoutManager(layoutManager);
items.setAdapter(adapter);
}
class Holder extends RecyclerView.ViewHolder{
CardView cardView;
public Holder(#NonNull View itemView) {
super(itemView);
cardView = itemView.findViewById(R.id.card_view);
}
void bind (){
cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
adapter.notifyItemChanged(getAdapterPosition());
}
});
cardView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
return true;
}
});
}
}
class Adapter extends RecyclerView.Adapter<Holder>{
#NonNull
#Override
public Holder onCreateViewHolder(#NonNull ViewGroup viewGroup, int position) {
LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
return new Holder(layoutInflater.inflate(R.layout.item, viewGroup, false));
}
#Override
public void onBindViewHolder(#NonNull Holder holder, int position) {
holder.bind();
}
#Override
public int getItemCount() {
return 30;
}
}
}
And here's the item.xml
<?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:layout_width="match_parent"
android:layout_height="160dp"
>
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="10dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:cardCornerRadius="8dp"
app:cardElevation="5dp"
android:stateListAnimator="#null"
>
</android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>
I have a simple RecyclerViewer that has 30 items and each item has a CardView with 10dp margin and a cardElevation of 5dp just to have some nice shadow.
When an item gets clicked the recyclerview adapter receives a notifyItemChanged(getAdapterPosition()) and on long click all items receives a change event via a notifyItemRangeChanged(0, adapter.getItemCount()) call to the adapter;
With the DefaultItemAnimator whenever an item gets "changed" the CardView shadow gets animated bigger during the transition animation. I want to keep the transition as I'm doing some updates in the item but I don't want to have the shadow/elevation animation.
You can see the outcome here:
https://gph.is/g/ajmNGen
Think that on long click the application moves into a "multi select" mode where all the items have big changes in layout and I want this change to be animated (by the DefaulItemAnimator) and I would like to keep the shadow as set originally.
Any help is really appreciated guys as I'm pulling my hair while dealing with this.
Set a constraint layout inside cardView, then you can clearly see the shadow:-
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:elevation="6dp"
tools:context=".MainActivity">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>

Potential Glide bug - RecyclerView item lose focus when fast scrolled with Dpad on Android TV

I am attempting to make a basic photo album app for Android TV.
Using recyclerview with glide.
Issue:
When scrolling one by one slowly by pressing dpad down button, recyclerview items gain focus accurately just as expected. But when dpad down button is kept pressed, during fast scroll, recyclerview item easily lose focus and the focus is moved to any focusable view (in this case an edit text) outside the recyclerview and no scrolling is possible until manually focus is moved inside recyclerview again.
Remedies attempted:
1. If I disable image loading by Glide completely (inside onBindViewHolder()), focus is never lost and no matter how fast the scrolling is it always works as expected. This remedy is not useful as images needs to be viewed.
2. If fast scrolling is limited by overriding Activity.onKeyDown method to ignore all key inputs unless 300ms has passed since last keydown it works. Again, this feels very hacky and completely disables fast scroll with is an absolute requirement.
Please note that I have already read the related QA on stackoverflow. Which suggested it's a bug in Android support library LayoutManager code which is not the case here since without glide it works fine.
How to reproduce: Create a fragment like ListFragment (code below) and try fast scrolling by keeping Down Dpad button pressed and you will see that editText constantly getting focused.
Code:
ListFragment.java
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.request.RequestOptions;
import java.util.Random;
public class ListFragment extends Fragment {
RequestManager glide;
public ListFragment() {
// Required empty public constructor
}
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
#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
return inflater.inflate(R.layout.fragment_list, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView = getActivity().findViewById(R.id.my_recycler_view);
glide = Glide.with(this);
layoutManager = new GridLayoutManager(getActivity(),8);
mAdapter = new MyAdapter();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(mAdapter);
}
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private final String[] imageUrls = {"https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa1821c67c1430401c65/1546365481213/20181208_0034pp2+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa218a922d1c5eb370c5/1546365483758/20181208_0115pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba92340ec9ab2ea3f0f73/1546365229886/20181215_0135pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8880e2e72e38d92a482/1546365075745/20180914_0189+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba885f950b760dd6800a7/1546365086762/20180914_0168pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba9b1032be425c6948ca2/1546365375849/20180818_0014pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa184ae2379d323c4187/1546365481929/20181208_0065pp+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256b9e4fcb574ae612941/1470258368357/20160801_0045.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255d1e4fcb574ae61196f/1470256635728/20160717_0391.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25695e4fcb574ae61273c/1470258368265/20160801_0040.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256dbe4fcb574ae612b71/1470258369606/20160801_0108+pp+810+bw.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257088419c29f345a7500/1470258369115/20160801_0108+pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4f950b760dd6804fe/1546365168544/20181101_0067pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba83270a6adae0b3b6395/1546364992480/20181205_0164pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4575d1f0c318f3727/1546365171139/20181101_0050pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2543dd1758e06589e07f1/1470256544677/20160402_0075+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a253fad1758e06589e040f/1470256190368/20160402_0039+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255fae4fcb574ae611e08/1470258367476/20160717_0444b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2573be4fcb574ae613197/1470258370169/20160801_0123+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257708419c29f345a7ba7/1470258369404/20160801_0272+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25db19f74561d105005de/1470258684806/20160402_0046+810+nik2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/55076c74e4b07b36ea118be0/1470413754677/20141222_0049.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256688419c29f345a6b17/1470258368620/20160721_0097+pp2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255c9d1758e06589e1f5e/1470258367695/20160721_0012+ppb.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c21ac72b8dde5db5879498/1546363401197/20151107_0094+pp+57c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c20eb662cd945cd5b485f5/1546363401197/20151024_1026+pp+810c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/53558987e4b007661e339aa7/1470413754809/20140419_0430_pp1+5x7b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db7f3893fc0e1cdfe1bbb/1482536961660/20160507_0069b+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8019de4bb91b69d5e37/1482537012182/20160904_0012+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8346a496340ce2b8f6e/1482537056393/20160904_0043+pp+810l.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db846d482e9c87e69aa3c/1482537056630/20160904_0071+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db860d2b857ddbd63c824/1482537071373/20160904_0119+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8602e69cf4bac703ff9/1482537081308/20160904_0124+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8828419c2d595b13ee0/1482537109350/20161008_0086+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8923e00be46604ad66c/1482537119283/20161105_0068pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db895b3db2b35c2346e97/1482537128208/20161128_0181+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db89fc534a5283f35edd0/1482537156287/20161203_0126+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8a703596eeb52691ac2/1482537145676/20161206_0101.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa1821c67c1430401c65/1546365481213/20181208_0034pp2+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa218a922d1c5eb370c5/1546365483758/20181208_0115pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba92340ec9ab2ea3f0f73/1546365229886/20181215_0135pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8880e2e72e38d92a482/1546365075745/20180914_0189+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba885f950b760dd6800a7/1546365086762/20180914_0168pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba9b1032be425c6948ca2/1546365375849/20180818_0014pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa184ae2379d323c4187/1546365481929/20181208_0065pp+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256b9e4fcb574ae612941/1470258368357/20160801_0045.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255d1e4fcb574ae61196f/1470256635728/20160717_0391.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25695e4fcb574ae61273c/1470258368265/20160801_0040.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256dbe4fcb574ae612b71/1470258369606/20160801_0108+pp+810+bw.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257088419c29f345a7500/1470258369115/20160801_0108+pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4f950b760dd6804fe/1546365168544/20181101_0067pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba83270a6adae0b3b6395/1546364992480/20181205_0164pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4575d1f0c318f3727/1546365171139/20181101_0050pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2543dd1758e06589e07f1/1470256544677/20160402_0075+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a253fad1758e06589e040f/1470256190368/20160402_0039+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255fae4fcb574ae611e08/1470258367476/20160717_0444b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2573be4fcb574ae613197/1470258370169/20160801_0123+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257708419c29f345a7ba7/1470258369404/20160801_0272+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25db19f74561d105005de/1470258684806/20160402_0046+810+nik2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/55076c74e4b07b36ea118be0/1470413754677/20141222_0049.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256688419c29f345a6b17/1470258368620/20160721_0097+pp2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255c9d1758e06589e1f5e/1470258367695/20160721_0012+ppb.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c21ac72b8dde5db5879498/1546363401197/20151107_0094+pp+57c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c20eb662cd945cd5b485f5/1546363401197/20151024_1026+pp+810c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/53558987e4b007661e339aa7/1470413754809/20140419_0430_pp1+5x7b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db7f3893fc0e1cdfe1bbb/1482536961660/20160507_0069b+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8019de4bb91b69d5e37/1482537012182/20160904_0012+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8346a496340ce2b8f6e/1482537056393/20160904_0043+pp+810l.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db846d482e9c87e69aa3c/1482537056630/20160904_0071+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db860d2b857ddbd63c824/1482537071373/20160904_0119+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8602e69cf4bac703ff9/1482537081308/20160904_0124+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8828419c2d595b13ee0/1482537109350/20161008_0086+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8923e00be46604ad66c/1482537119283/20161105_0068pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db895b3db2b35c2346e97/1482537128208/20161128_0181+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db89fc534a5283f35edd0/1482537156287/20161203_0126+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8a703596eeb52691ac2/1482537145676/20161206_0101.jpg"};
private final RequestOptions options = new RequestOptions().centerCrop();
private final Random random = new Random();
private final Handler handler = new Handler();
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView icon;
public View layout;
ViewHolder(View v) {
super(v);
layout = v;
icon = v.findViewById(R.id.icon);
}
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
LayoutInflater inflater = LayoutInflater.from(
parent.getContext());
View v =
inflater.inflate(R.layout.item_recycler_view, parent, false);
MyAdapter.ViewHolder vh = new MyAdapter.ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder holder, final int position) {
final String name = imageUrls[random.nextInt(imageUrls.length - 1)];
//Commenting this out resolves focus loss
glide.load(name).into(holder.icon);
}
#Override
public void onViewRecycled(#NonNull ViewHolder holder) {
super.onViewRecycled(holder);
glide.clear(holder.icon);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
}
}
Layouts:
item_recycler_view.xml
<?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="wrap_content"
android:foreground="#drawable/fg_selectable"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="false"
android:descendantFocusability="blocksDescendants"
android:layout_margin="2dp"
>
<ImageView
android:id="#+id/icon"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="27:41"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="#color/colorPrimaryDark"
tools:src="#tools:sample/avatars"
/>
</android.support.constraint.ConstraintLayout>
fragment_list.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ListFragment"
android:orientation="horizontal"
>
<EditText
android:id="#+id/editText"
android:text="test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:nextFocusDown="#id/editText"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
Why do you need glide.clear() in onViewRecycled? My guess is that it has to do with frequent glide loading and clearing during fast scrolls. Glide may be getting somewhat confused. Also, why not Leanback Library and GridFragment? From my experience it works just fine with Glide and fast scrolling.

Elevated RecyclerView items get progressively deformed (elevation changes)

Any idea why RecyclerView items get deformed , each consecutive item gets worse?
UPDATE: I'm using CardViews and now there's no view "deformation" but the shadow/elevation height changes.
It seems that elevation gets higher depending on where on the screen the item is located vertically, the shadow grows as the item gets scrolled down. Please see the video here: https://youtu.be/nROYq8rpUMs.
I've set up a new project leaving only the code necessary to demonstrate the issue:
MainActivity.java
package tzig.schm00.masterdetail;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import tzig.schm00.masterdetail.dummy.DummyContent;
import java.util.List;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View recyclerView = findViewById(R.id.item_list);
setupRecyclerView((RecyclerView) recyclerView);
}
private void setupRecyclerView(#NonNull RecyclerView recyclerView) {
recyclerView.setAdapter(new SimpleItemRecyclerViewAdapter(DummyContent.ITEMS));
}
public class SimpleItemRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> {
private final List<DummyContent.DummyItem> mValues;
public SimpleItemRecyclerViewAdapter(List<DummyContent.DummyItem> items) {
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.mIdView.setText(mValues.get(position).id);
holder.mContentView.setText(mValues.get(position).content);
}
#Override
public int getItemCount() {
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final TextView mIdView;
public final TextView mContentView;
public DummyContent.DummyItem mItem;
public ViewHolder(View view) {
super(view);
mView = view;
mIdView = (TextView) view.findViewById(R.id.id);
mContentView = (TextView) view.findViewById(R.id.content);
}
#Override
public String toString() {
return super.toString() + " '" + mContentView.getText() + "'";
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/item_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context="tzig.schm00.myapplication.MainActivity" />
</FrameLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/cont_item_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="8dp"
card_view:cardElevation="10dp"
card_view:cardMaxElevation="10dp"
card_view:cardUseCompatPadding="true">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
<TextView
android:id="#+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
</LinearLayout>
</android.support.v7.widget.CardView>
New observation: seems like it's a standard behavior. Looks the same with the Image Picker displaying folders using CardViews...
Any help is greatly appreciated!
Thanks!!
This is how it's intended to be according to Material Design: Environment: Light and shadows: Light.
Also see answer https://stackoverflow.com/a/51216164/6685260
Add a background to your RelativeLayout - seems that elevation needs it to work properly. I have tested this with your layout and it does work.
I had the same issue, and in my case the problem was caused by a background drawable which I set in my RecyclerViewAdapter#onBindViewHolder:
// this spoiled the shadows!
cardView.setBackgroundDrawable(ContextCompat.getDrawable(context, myColorResourceId);
After I removed the line above the problem has disappeared!
(To have both a background and nice shadows I used an inner element filling the CardView and applied background to it instead of CardView)

Using a layout xml as a template of repeated content in Android

I have a template layout which represents each of my rows in a ListView in my app.
Here is the photorow.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/bodylay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<ImageView
android:id="#+id/leftbigsquare"
android:layout_width="0dp"
android:layout_height="140dp"
android:layout_weight="1"
android:background="#1000b0"
android:src="#drawable/test1"
/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#d0b0b0"
android:textSize="15sp" >
<ImageView
android:id="#+id/righttupperleft"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#b170b0"
android:src="#drawable/test1" />
<ImageView
android:id="#+id/rightupperright"
android:layout_width="0dp"
android:layout_height="70dp"
android:layout_weight="1"
android:background="#b110b0"
android:src="#drawable/test1" />
</LinearLayout>
<ImageView
android:id="#+id/righthorizontal"
android:layout_width="match_parent"
android:layout_height="70dp"
android:src="#drawable/test1" />
</LinearLayout>
It is repeated row by row. What I want to do is to change "ImageView" child, when I load the image from my server not redesign the row layout each time. Each row will show different "leftbigsquare", "rightupperleft", "rightupperright", "righthorizontal" (look at ImageViews ids) photos.
I researched and saw some examples, but they did that by hardcoding the layout such as :
LinearLayout A = new LinearLayout(this);
A.setOrientation(LinearLayout.HORIZONTAL);
I want to use my photorow.xml as template and just change its attributes such as source in each row.
Is it possible to use my photorow.xml as the template of a row ?
EDIT
My custom adapter :
package com.example.test2;
import java.util.List;
import com.squareup.picasso.Picasso;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class PhotoAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private List<PhotoRow> rowList;
Activity context = null;
public PhotoAdapter(Activity activity, List<PhotoRow> rows) {
mInflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowList = rows;
context = activity;
}
#Override
public int getCount() {
return rowList.size();
}
#Override
public Object getItem(int position) {
return rowList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView;
rowView = mInflater.inflate(R.layout.photorow, null);
//Here I get the ImageView of my photorow xml
ImageView leftBigSquare = (ImageView) rowView
.findViewById(R.id.leftbigsquare);
// Here I get the proper URL from rowList by using Picasso framework
Picasso.with(context).load(rowList.get(position).getUrls().get(0))
.resize(50, 50).centerCrop().into(leftBigSquare);
//So how can I put the leftBigSquare ImageView to my photorow template with its proper attributes
return rowView;
}
}
Yes, of course, you can use same rowview XML and still have different data in every row.
You must use a custom adapter and then inflate your row s from that adapter and based on several conditions change your data.
Paste your custom adapter code and I will show you how to do it.

Categories

Resources