I am using for loop, and I have around 20 items displaying in recycler view! Now how do I hide/show image view as for loop runs... Here tts is working fine, but when i try to show/hide using this its not happening..
Presently with below code, once for loops ends the entire imageview is affecting, i want it a row wis(show current(image1) & hide previous imageview(image) )
I am calling this method from main Activity class, but the imageview show or hide not happening
activity
......
......
private void ConvertTextToSpeech() {
// TODO Auto-generated method stub
//items.forEach( Multiples obj -> System.out.println());
int z=0;
View holder=null; ImageView imageView=null;ImageView imageView1=null;
for (Multiples p : items) {
if(z>0){
holder = recyclerView.findViewHolderForAdapterPosition(z).itemView;
holder.findViewById(R.id.image).setVisibility(View.VISIBLE);
holder.findViewById(R.id.image1).setVisibility(View.INVISIBLE);
}
if(z < items.size()) {
holder = recyclerView.findViewHolderForAdapterPosition(z).itemView;
holder.findViewById(R.id.image).setVisibility(View.INVISIBLE);
holder.findViewById(R.id.image1).setVisibility(View.VISIBLE);
}
text = p.first + " " + p.getSecond() + " Za "+p.getResult()+".";
tts.speak(text, TextToSpeech.QUEUE_ADD, null);
z++;
}
}
xml
<?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">
<com.balysv.materialripple.MaterialRippleLayout
android:id="#+id/lyt_parent"
style="#style/RippleStyleBlack"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:focusable="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#color/grey_10" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:orientation="horizontal"
android:textAlignment="gravity" >
<View
android:layout_width="#dimen/spacing_large"
android:layout_height="wrap_content" />
<ImageView
android:id="#+id/image"
android:layout_width="35dp"
android:layout_height="35dp"
android:background="#android:color/transparent"
android:src="#drawable/ic_arrow_right" />
<ImageView
android:id="#+id/image1"
android:layout_width="51dp"
android:layout_height="35dp"
android:background="#android:color/transparent"
android:src="#drawable/ic_arrow_right"
android:visibility="invisible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="#dimen/spacing_middle"
android:paddingTop="#dimen/spacing_middle">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="#dimen/spacing_middle"
android:layout_marginRight="#dimen/spacing_middle"
android:fontFamily="sans-serif-condensed"
android:gravity="center|left"
android:text="36"
android:textAppearance="#style/TextAppearance.AppCompat.Medium"
android:textColor="#color/grey_80"
android:textSize="30sp"
/>
</LinearLayout>
<View
android:layout_width="#dimen/spacing_large"
android:layout_height="match_parent" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#color/grey_10" />
</LinearLayout>
</com.balysv.materialripple.MaterialRippleLayout>
</RelativeLayout>
adapter
public class AdapterListAnimation extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Multiples> items = new ArrayList<>();
private Context ctx;
private OnItemClickListener mOnItemClickListener;
private int animation_type = 0;
.........
.........
You need just add field in your adapter where you will save currently active item. Then call notifyDataSetChanged.
Also you should update your onBindViewHolder like this:
private int currentPosition = -1;
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
holder.textView.setText(items.get(position));
if (currentPosition == position) {
holder.img1.setVisibility(View.INVISIBLE);
holder.img2.setVisibility(View.VISIBLE);
} else {
holder.img1.setVisibility(View.VISIBLE);
holder.img2.setVisibility(View.INVISIBLE);
}
}
public void setCurrentPosition(int currentPosition) {
this.currentPosition = currentPosition;
}
I've created a test project to show how it can be implemented. Here you can see how it works. Here is my github repository.
You should not directly change the item view state inside the adapter with the following:
holder = recyclerView.findViewHolderForAdapterPosition(z).itemView;
holder.findViewById(R.id.image).setVisibility(View.VISIBLE);
holder.findViewById(R.id.image1).setVisibility(View.INVISIBLE);
instead, you need to use a specific method to tell the RecyclerView adapter that you need to change a state of an item view.
Be noted, that RecylerView naturally (in programmatically way) will recyler it's previous item whenever it needs to draw another item. So, you need to keep the state of each item whether using a specific variable inside your model or using a variable to hold each item state.
In case that you don't want to change your model, you can use SparseBooleanArray to hold the state. You can do something like this in your Adapter:
public class YourAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Multiples> mItems;
// We use this to hold the image state.
private SparseBooleanArray mImageStates;
public YourAdapter(List<Multiples> items) {
this.mItems = items;
mImageStates = new SparseBooleanArray();
...
}
#Override
public YourAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
...
return viewHolder;
}
#Override
public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
int itemPosition = viewHolder.getAdapterPosition();
Multiples item = mItems.get(itemPosition);
// Load the state by the previous saved state
// default value is false.
if(mImageStates.get(itemPosition)) {
// show the images or something.
} else {
// hide the images or something.
}
}
public void setState(int position, boolean isVisible) {
mImageStates.put(position, isVisible);
}
}
now you can change the state item visibility with:
yourAdapter.setState(yourItemPosition, true);
then notify the adapter about the change with:
yourAdapter.notifyItemChanged(yourItemPosition);
or reset all if you have change many items with:
yourAdapter.notifyDataSetChanged();
you have to write a logic on onbindholder then.
onBindHolder(ViewHolder holder, int position){
if(position %2==0)
imageview.setVisibility(View.Visible);
else
imageview.setVisibility(View.InVisible);
}
Finally Got the Solution
I have added two parameters in your Multiples. In your loop when a condition is true, I am setting variable according to you have done with Image view. after I am notifying RecyclerView. so, a callback will come on onBindViewHolder. there I have added conditions for show/hide Image view.
suppose left Arrow is image & right Arrow is image1
NOTE: Android Default TextToSpeech does not provide any event listener for complete. So, I have tried a new library that is well maintained and provide Speech recognition and Text to speech functionality.
Gradle:
implementation 'net.gotev:speech:1.4.0'
Initialization:
To start using the library, you have to initialize it in your Activity.
public class YourActivity extends Activity {
private count = 0;
private maxCount = 0;
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
Speech.init(this, getPackageName());
maxCount = items.size();
}
#Override
protected void onDestroy() {
// prevent memory leaks when activity is destroyed
Speech.getInstance().shutdown();
}
}
public class Multiples implements Serializable {
private Boolean isShowimage = false;
private Boolean isShowimage1 = false;
public Boolean getShowimage() {
return isShowimage;
}
public void setShowimage(Boolean showimage) {
isShowimage = showimage;
}
public Boolean getShowimage1() {
return isShowimage1;
}
public void setShowimage1(Boolean showimage1) {
isShowimage1 = showimage1;
}
}
private void ConvertTextToSpeech() {
if (count < maxCount) {
reset();
String text = items.get(count).first + " " + items.get(count).getSecond() + " Za " + items.get(count).getResult() + ".";
Speech.getInstance().say(text, new TextToSpeechCallback() {
#Override
public void onStart() {
Log.i("speech", "speech started");
items.get(count).setShowimage(false);
items.get(count).setShowimage1(true);
adapter.notifyDataSetChanged();
}
#Override
public void onCompleted() {
Log.i("speech", "speech completed");
ConvertTextToSpeech();
count++;
}
#Override
public void onError() {
Log.i("speech", "speech error");
}
});
}
}
private void reset() {
for (Multiples p : items) {
p.setShowimage(true);
p.setShowimage1(false);
}
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
final Multiples item = items.get(position);
if (item.getShowimage()) {
holder.image.setVisibility(View.VISIBLE);
} else {
holder.image.setVisibility(View.INVISIBLE);
}
if (item.getShowimage1()) {
holder.image1.setVisibility(View.VISIBLE);
} else {
holder.image1.setVisibility(View.INVISIBLE);
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView,imageView1;
public ViewHolder(View view) {
super(view);
this.imageView = (ImageView) view.findViewById(R.id.imageView);
this.imageView1 = (ImageView) view.findViewById(R.id.imageView1);
}
}
Related
I am creating Android app, using room database.
I have two tables DogsTable:
#PrimaryKey(autoGenerate = true)
int dog_id;
String dogName;
and CatsTable (both tables have constructor and getter methods ):
#PrimaryKey(autoGenerate = true)
int cat_id;
String catName;
1- How to display in one RecyclerView two different object type
ArrayList<DogsTable> dog_list;
ArrayList<CatsTable> cat_list;
I am getting the values of dog_list and cat_list from ViewModel Query as show in MainActivity.class.
2- How to fix getItemCount() method? I don't know how to return two different object cat_list.size(); and dog_list.size();
3- Also in onBindViewHolder() method I don`t know how to get cat_list values to display them in UI?
4- Another problem is in swapToDelete() Method in MainActivity.class, I can get the dog id to delete it, but I can not get the cat id to delete it, how can I get the cat id ?
5- How can I display (dog1,dog2 , dog3) as show in first image? (i inserted the value manually in the first image just to show how i want to display them )
Existing Output as below:
My code
MainActivity.java
public class MainActivity extends AppCompatActivity implements MainActivityAdapter.ItemClickListener {
MyViewModel viewModel;
MainActivityAdapter adapter;
RecyclerView recyclerView;
LinearLayoutManager layoutManager;
Button btn_addDog, btn_addCat;
EditText et_addDogName, et_addCatName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
actionButton();
buildRecyclerView();
setUpViewModel_dogs();
swapToDelete_dog();
}
private void initViews() {
et_addDogName = findViewById(R.id.addDogNameET_xml);
et_addCatName = findViewById(R.id.addCatNameET_xml);
}
public void actionButton() {
btn_addDog = findViewById(R.id.AddDog_btn_xml);
btn_addCat = findViewById(R.id.AddCat_btn_xml);
btn_addDog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
insertDog();
}
});
btn_addCat.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
insertCat();
}
});
}
private void buildRecyclerView() {
recyclerView = findViewById(R.id.recyclerView_id);
adapter = new MainActivityAdapter(this, this);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
// Query
public void setUpViewModel_dogs() {
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
viewModel.getAllDogs().observe(this, new Observer<List<DogsTable>>() {
#Override
public void onChanged(#Nullable List<DogsTable> dogsTables) {
adapter.setDog_list((ArrayList<DogsTable>) dogsTables);
}
});
}
public void setUpViewModel_cats(){
viewModel.getAllCats().observe(this, new Observer<List<CatsTable>>() {
#Override
public void onChanged(#Nullable List<CatsTable> catsTables) {
adapter.setCat_list((ArrayList<CatsTable>) catsTables);
}
});
}
// Add
public void insertDog() {
String dogName = String.valueOf(et_addDogName.getText()).trim();
DogsTable obj_dog = new DogsTable(dogName);
viewModel.insertDog(obj_dog);
Toast.makeText(this, "Dog Added", Toast.LENGTH_SHORT).show();
}
public void insertCat() {
String catName = String.valueOf(et_addCatName.getText());
CatsTable obj_cat = new CatsTable(catName);
viewModel.insertCat(obj_cat);
Toast.makeText(this, "cat Added", Toast.LENGTH_SHORT).show();
}
// Delete
public void swapToDelete_dog() {
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
List<DogsTable> dog_pos = adapter.getDog_list();
viewModel.deleteDog(dog_pos.get(viewHolder.getAdapterPosition()));
}
}
).attachToRecyclerView(recyclerView);
}
public void swapToDelete_cat() {
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int item_id = item.getItemId();
if (item_id == R.id.menu_add) {
Intent in = new Intent(this, Add.class);
startActivity(in);
}
return super.onOptionsItemSelected(item);
}
#Override
public void onItemClickListener(int pet_id) {
}
}
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"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/addDogNameET_xml"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:hint="add Dog name" />
<Button
android:id="#+id/AddDog_btn_xml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="#+id/addCatNameET_xml"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:hint="add Cat name" />
<Button
android:id="#+id/AddCat_btn_xml"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="add" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints" />
</LinearLayout>
MainActivityAdapter.java
public class MainActivityAdapter extends RecyclerView.Adapter<MainActivityAdapter.MyViewHolder> {
Context mContext;
ArrayList<DogsTable> dog_list;
ArrayList<CatsTable> cat_list;
ItemClickListener mItemClickListener;
public MainActivityAdapter(Context context , ItemClickListener itemClickListener) {
this.mContext = context;
this.mItemClickListener = itemClickListener;
}
public interface ItemClickListener {
void onItemClickListener(int pet_id);
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.activity_main_adapter, viewGroup, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
DogsTable dog_pos = dog_list.get(position);
// CatsTable catsTable = cat_list.get(position);
holder.dogName.setText(String.valueOf(dog_pos.getDogName()));
// holder.catName.setText(String.valueOf(catsTable.getCatName()));
}
#Override
public int getItemCount() {
if (dog_list == null ) {
return 0;
} else {
return dog_list.size();
}
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener , ItemClickListener {
TextView dogName;
TextView catName;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
dogName = itemView.findViewById(R.id.dogName_xml);
catName = itemView.findViewById(R.id.catName_xml);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int pet_id = dog_list.get(getAdapterPosition()).getDogs_id();
mItemClickListener.onItemClickListener(pet_id);
}
#Override
public void onItemClickListener(int pet_id) {
int pos = dog_list.get(getAdapterPosition()).getDogs_id();
mItemClickListener.onItemClickListener(pet_id);
}
}
public void setDog_list(ArrayList<DogsTable> dog_list) {
this.dog_list = dog_list;
notifyDataSetChanged();
}
public ArrayList<DogsTable> getDog_list() {
return dog_list;
}
public void setCat_list(ArrayList<CatsTable> cat_list) {
this.cat_list = cat_list;
}
}
activity_main_adapter.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:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dogs: " />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/dogName_xml"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cats: " />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="#+id/catName_xml"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
To support different view types, RecyclerView.Adapter provides a useful method int getItemViewType(int position):
Return the view type of the item at position for the purposes of view recycling.
The default implementation of this method returns 0, making the assumption of a single view type for the adapter. Unlike ListView adapters, types need not be contiguous. Consider using id resources to uniquely identify item view types.
Then, in onCreateViewHolder you can see that a second parameter is int viewType which comes from the method int getItemViewType(int position). Based on that, you can instantiate a ViewHolder you need, e.g. DogViewHolder or CatViewHolder.
But what about storing multiple view models in a single adapter and defining which ViewHolder type should be actually instantiated? Here are two most popular approaches:
Declaring multiple containers for multiple types and defining a custom logic for getItemViewType method, e.g. all odd numbers will go in the dogs' list and even numbers will go in the cats' list (or any other method, but beware that you will have to cope with different lists' sizes and all the view types you need). Also, getItemsCount should be overriden appropriately (return list1.size() + list2.size + ... + listN.size();)
Put all the view models in a single list and perform some kind of attributes checks: either it will be some property or the type itself (not recommended for scalability reasons). Then your code will look like this:
public int getItemViewType(int position) {
CommonParentForUpcasting item = items.get(position);
if (item instanceOf Dog) { // or something like item.type == Animal.CAT
return R.id.holder_dog;
} else {
return R.id.holder_cat;
}
}
If you want to come up with a second solution, this solution should suit you well.
Also, make sure to check this StackOverflow answer.
App gets data from an api and populates it in a recyclerview. The
recyclerview is in the mainactivity.xml which shows data in a cardview which is inflated from datacard.xml.
I want to change the text of a button which is in the datacard.xml from the MainActivity.java while clicking it.
I tried changing it from the DataCardAdapter and it works fine with similar code. But Its not happening from the MainActivity.
MainActivity.java
final LinearLayout mainView = (LinearLayout) findViewById(R.id.mainView);
LayoutInflater inflater = getLayoutInflater();
View dataCardView = inflater.inflate(R.layout.datacard, null);
actionButton=(Button) dataCardView.findViewById(R.id.buttonAction);
actionButton.setTag(ACTION_PLAY);
actionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String tag = (String) v.getTag();
if (v.getTag() == ACTION_PLAY){
Toast.makeText(v.getContext(), " PLAY " , Toast.LENGTH_SHORT).show();
actionButton.setText("PAUSE");
actionButton.setTag(ACTION_PAUSE);
}else if (v.getTag() == ACTION_PAUSE){
Toast.makeText(v.getContext(), " PAUSE " , Toast.LENGTH_SHORT).show();
actionButton.setTag(ACTION_PLAY);
actionButton.setText("PLAY");
}
}
});
....
public void ACTION_PARSE_DATA_AFTER_WEBCALL(JSONArray array) {
for (int i = 0; i < array.length(); i++) {
....
......
.......
} catch (JSONException e) {
e.printStackTrace();
}
DataAdapterClassList.add(GetDataModel);
}
if (array.length() != 0) {
recyclerViewAdapter2 = new DataAdapter(DataAdapterClassList, this);
recyclerView2.setAdapter(recyclerViewAdapter2);
}
}
mainactivity.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="vertical"
android:background="#color/colorSplashText"
android:id="#+id/mainView">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</ScrollView>
</RelativeLayout>
datacard.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.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:id="#+id/Card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="4dp"
app:cardBackgroundColor="#color/design_default_color_on_primary"
app:cardCornerRadius="10dp"
app:cardElevation="2dp"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/constrainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
<Button
android:id="#+id/buttonAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="6dp"
android:text="PLAY" />
</androidx.constraintlayout.widget.ConstraintLayout>
DataCardAdapter
public class DataCardAdapter extends RecyclerView.Adapter<EventsAdapter.ViewHolder> {
Context context;
private static final String ACTION_PLAY = "play";
private static final String ACTION_PAUSE = "pause";
public List<EventsDataModel> eventsDataModels;
public EventsAdapter(List<EventsDataModel> getDataAdapter, Context context) {
super();
this.eventsDataModels = getDataAdapter;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.datacard, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
final EventsDataModel dataAdapter = eventsDataModels.get(position);
......
.......
// viewHolder.actionButton.setTag(ACTION_PLAY);
// viewHolder.actionButton.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
// String tag = (String) v.getTag();
// if (v.getTag() == ACTION_PLAY){
// //Toast.makeText(getContext(), "play",Toast.LENGTH_LONG).show();
// Toast.makeText(v.getContext(), " PLAY " , Toast.LENGTH_SHORT).show();
// viewHolder.actionButton.setText("PAUSE");
// viewHolder.actionButton.setTag(ACTION_PAUSE);
// }else if (v.getTag() == ACTION_PAUSE){
// Toast.makeText(v.getContext(), " PAUSE " , Toast.LENGTH_SHORT).show();
// viewHolder.actionButton.setTag(ACTION_PLAY);
// viewHolder.actionButton.setText("PLAY");
// }
// }
// });
}
class ViewHolder extends RecyclerView.ViewHolder {
private Button actionButton;
public ViewHolder(View itemView) {
super(itemView);
actionButton = (Button) itemView.findViewById(R.id.buttonAction);
}
}
}
You cannot do it this way. You should store that information in adapter.
RecyclerView will reuse (recycle) views to display data. This is why it is called recycler view.
Lets say you clicked first item and changed its state to PAUSE (PAUSE is stored in textview's tag). Then you scroll down and recyclerView instead of inflating another view it will reuse first view (as first item is no longer visible). So it will override the tag and text of this textView with new data.
When you will scroll back to the first item it will put data back again but it will use data from adapter.
The solution is to store that state in the adapter. And invalidate item when you click it (so it will redraw that item).
So when you click item you should do something more or less like that:
adapter.items.get(position).state="PLAY"
adapter.notifyItemChanged(position);
You can store position in tag)
You can do it from DataCardAdapter
create one method in DataCardAdapter where you have an axis of button so you can change the name of button ,
public changeButtonName(String buttonName){
//Here you can set new button name
notifyDataSetChanged();
}
call this method from MainActivity by using Object of Adapter , please first check adapter object should not be null.
You can access adapter's view from activity if you have position of item in activity like below code
if(recyclerViewThemes.findViewHolderForAdapterPosition(Your item position here)!=null)
{
View tempView = recyclerViewThemes.findViewHolderForAdapterPosition(Your item position here).itemView;
Button btn = tempView.findViewById(R.id.btn);
btn.setText("Your text here");
}
recyclerViewThemes.getAdapter().notifyItemChanged(i);//notify your adapter
I am trying to use a swipeCallback on a list with modeladapter. In order to make it work, I stripped down all my customization and modeled it close to the sample app, but the combination produces the error of not allowing undo. When I swipe, this happens:
The swipe works, but the undo icon does not show up. Any ideas what I am doing wrong? The underlying fragment is this:
public class EditFragment extends Fragment implements ItemTouchCallback, SimpleSwipeCallback.ItemSwipeCallback {
private FragmentEditBinding oBinding;
private SongViewModel oViewModel;
//save our FastAdapter
private FastAdapter fastAdapter;
private ModelAdapter<ModelSongCounter, ModelItemView> itemAdapter;
//drag & drop
private SimpleDragCallback touchCallback;
private ItemTouchHelper touchHelper;
public EditFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//init Databinding
oBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_edit, container, false);//.setContentView(getActivity(), R.layout.fragment_main);
//LayoutInflaterCompat.setFactory(getLayoutInflater(), new IconicsLayoutInflater(getActivity()));
//style our ui
new MaterializeBuilder().withActivity(getActivity()).build();
//adapters
//FastScrollIndicatorAdapter fastScrollIndicatorAdapter = new FastScrollIndicatorAdapter();
itemAdapter = new ModelAdapter<>(new IInterceptor<ModelSongCounter, ModelItemView>() {
#Override
public ModelItemView intercept(ModelSongCounter iconModel) {
return new ModelItemView(iconModel);
}
});
//create our FastAdapter which will manage everything
fastAdapter = FastAdapter.with(Arrays.asList(itemAdapter));
fastAdapter.withSelectable(true);
//get our recyclerView and do basic setup
//RecyclerView rv = oBinding.SongRecyclerView;
oBinding.SongRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
//oBinding.SongRecyclerView.setItemAnimator(new SlideDownAlphaAnimator());
oBinding.SongRecyclerView.setAdapter(fastAdapter);
//get ViewModels from Provider
oViewModel = ViewModelProviders.of(getActivity()).get(SongViewModel.class);
//get rid of the annoying blink
oBinding.SongRecyclerView.setItemAnimator(null);
//add Observer to ViewModel
// The onChanged() method fires when the observed data changes and the activity is
// in the foreground.
oViewModel.getAllCatsLive().observe(this, new Observer<List<ModelSongCounter>>() {
#Override
public void onChanged(#Nullable List<ModelSongCounter> modelSongCounters) {
itemAdapter.set(modelSongCounters);
}
});
fastAdapter.withEventHook(new ClickEventHook<ModelItemView>() {
#Nullable
#Override
public View onBind(#NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof ModelItemView.ViewHolder) {
return ((ModelItemView.ViewHolder) viewHolder).Minus;
}
return null;
}
#Override
public void onClick(View v, int position, FastAdapter<ModelItemView> fastAdapter, ModelItemView item) {
//react on the click event
oViewModel.decrement(item.getModel().uid);
}
});
fastAdapter.withEventHook(new ClickEventHook<ModelItemView>() {
#Nullable
#Override
public View onBind(#NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof ModelItemView.ViewHolder) {
return ((ModelItemView.ViewHolder) viewHolder).Plus;
}
return null;
}
#Override
public void onClick(View v, int position, FastAdapter<ModelItemView> fastAdapter, ModelItemView item) {
//react on the click event
oViewModel.increment(item.getModel().uid);
}
});
//restore selections (this has to be done after the items were added
fastAdapter.withSavedInstanceState(savedInstanceState);
//Swipable stuff within OnCreateView
Drawable leaveBehindDrawableLeft = new IconicsDrawable(getContext())
.icon(MaterialDesignIconic.Icon.gmi_delete)
.color(Color.WHITE)
.sizeDp(24);
Drawable leaveBehindDrawableRight = new IconicsDrawable(getContext())
.icon(MaterialDesignIconic.Icon.gmi_archive)
.color(Color.WHITE)
.sizeDp(24);
touchCallback = new SimpleSwipeDragCallback(
this,
this,
leaveBehindDrawableLeft,
ItemTouchHelper.LEFT,
ContextCompat.getColor(getContext(), R.color.md_red_900)
)
.withBackgroundSwipeRight(ContextCompat.getColor(getContext(), R.color.md_blue_900))
.withLeaveBehindSwipeRight(leaveBehindDrawableRight);
touchHelper = new ItemTouchHelper(touchCallback); // Create ItemTouchHelper and pass with parameter the SimpleDragCallback
touchHelper.attachToRecyclerView(oBinding.SongRecyclerView); // Attach ItemTouchHelper to RecyclerView
//restore selections (this has to be done after the items were added
fastAdapter.withSavedInstanceState(savedInstanceState);
return oBinding.getRoot();
}
#Override
public void onSaveInstanceState(Bundle outState) {
//add the values which need to be saved from the adapter to the bundle
outState = fastAdapter.saveInstanceState(outState);
super.onSaveInstanceState(outState);
}
//Swipable...and probably relevant for expandables, since there is TouchOnMove
#Override
public boolean itemTouchOnMove(int oldPosition, int newPosition) {
//DragDropUtil.onMove((ItemAdapter)itemAdapter, oldPosition, newPosition); // change position
return true;
}
#Override
public void itemTouchDropped(int oldPosition, int newPosition) {
//f.e. save new order in database
}
#Override
public void itemSwiped(int position, int direction) {
// -- Option 1: Direct action --
//do something when swiped such as: select, remove, update, ...:
//A) fastItemAdapter.select(position);
//B) fastItemAdapter.remove(position);
//C) update item, set "read" if an email etc
// -- Option 2: Delayed action --
final ModelItemView item = itemAdapter.getAdapterItem(position);
item.setSwipedDirection(direction);
// This can vary depending on direction but remove & archive simulated here both results in
// removal from list
final Runnable removeRunnable = new Runnable() {
#Override
public void run() {
item.setSwipedAction(null);
int position = itemAdapter.getAdapterPosition(item);
if (position != RecyclerView.NO_POSITION) {
//this sample uses a filter. If a filter is used we should use the methods provided by the filter (to make sure filter and normal state is updated)
//fastItemAdapter.getItemFilter().remove(position);
itemAdapter.remove(position);
}
}
};
final View rv = oBinding.SongRecyclerView;
rv.postDelayed(removeRunnable, 3000);
item.setSwipedAction(new Runnable() {
#Override
public void run() {
rv.removeCallbacks(removeRunnable);
item.setSwipedDirection(0);
int position = itemAdapter.getAdapterPosition(item);
if (position != RecyclerView.NO_POSITION) {
fastAdapter.notifyItemChanged(position);
}
}
});
fastAdapter.notifyItemChanged(position);
//TODO can this above be made more generic, along with the support in the item?
}
}
This is the swipable ModelItem (the model "ModelSongCounter" is just a POJO):
public class ModelItemView
extends ModelAbstractItem<ModelSongCounter, ModelItemView, ModelItemView.ViewHolder>
implements ISwipeable<ModelItemView, IItem>, IDraggable<ModelItemView, IItem> {
public StringHolder undoTextSwipeFromLeft;
public int iSwipedDirection;
private Runnable rSwipedAction;
public boolean bSwipable = true;
public boolean draggable = true;
public ModelItemView(ModelSongCounter icon) {
super(icon);
}
/**
* defines the type defining this item. must be unique. preferably an id
*
* #return the type
*/
#Override
public int getType() {
return R.id.iconics_tag_id;
}
/**
* defines the layout which will be used for this item in the list
*
* #return the layout for this item
*/
#Override
public int getLayoutRes() {
return R.layout.item_view;
}
/**
* binds the data of this item onto the viewHolder
*
* #param viewHolder the viewHolder of this item
*/
#Override
public void bindView(ViewHolder viewHolder, List<Object> payloads) {
super.bindView(viewHolder, payloads);
//define our data for the view
viewHolder.name.setText(getModel().getName());
viewHolder.counter.setText(Integer.toString(getModel().getCounter()));
viewHolder.swipeResultContent.setVisibility(iSwipedDirection != 0 ? View.VISIBLE : View.GONE);
viewHolder.itemContent.setVisibility(iSwipedDirection != 0 ? View.GONE : View.VISIBLE);
CharSequence swipedAction = null;
CharSequence swipedText = null;
if(iSwipedDirection != 0){
swipedAction = viewHolder.itemView.getContext().getString(R.string.action_undo);
swipedText = iSwipedDirection == ItemTouchHelper.LEFT ? "Removed" : "Archived - Should not be implemented!";
viewHolder.swipeResultContent.setBackgroundColor(
ContextCompat.getColor(viewHolder.itemView.getContext(),
iSwipedDirection == ItemTouchHelper.LEFT ? R.color.md_red_900 : R.color.md_blue_900));
}
viewHolder.swipedAction.setText(swipedAction == null ? "" : swipedAction);
viewHolder.swipedText.setText(swipedText == null ? "" : swipedText);
viewHolder.rSwipedActionRunnable = this.rSwipedAction;
}
#Override
public void unbindView(ViewHolder holder) {
super.unbindView(holder);
holder.name.setText(null);
holder.counter.setText(null);
holder.swipedAction.setText(null);
holder.swipedText.setText(null);
holder.rSwipedActionRunnable = this.rSwipedAction;
}
#Override
public ViewHolder getViewHolder(View v) {
return new ViewHolder(v);
}
//SWipable
#Override
public boolean isSwipeable() {
return this.bSwipable;
}
#Override
public ModelItemView withIsSwipeable(boolean swipeableP) {
this.bSwipable = swipeableP;
return this;
}
public void setSwipedDirection(int iSwipedDirectionP){
this.iSwipedDirection = iSwipedDirectionP;
}
public void setSwipedAction(Runnable actionP){
this.rSwipedAction = actionP;
}
#Override
public boolean isDraggable() {
return draggable;
}
#Override
public ModelItemView withIsDraggable(boolean draggableP) {
this.draggable = draggableP;
return this;
}
/**
* our ViewHolder
*/
protected static class ViewHolder extends RecyclerView.ViewHolder {
protected View view;
#BindView(R.id.material_drawer_song)
public TextView name;
#BindView(R.id.material_drawer_counter)
public TextView counter;
#BindView(R.id.material_drawer_minus)
public ImageView Minus;
#BindView(R.id.material_drawer_plus)
public ImageView Plus;
#BindView(R.id.swipe_result_content)
public View swipeResultContent;
#BindView(R.id.item_content)
public View itemContent;
#BindView(R.id.swiped_text)
public TextView swipedText;
#BindView(R.id.swiped_action)
public TextView swipedAction;
public Runnable rSwipedActionRunnable;
public ViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
//this.view = view;// ?
swipedAction.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (rSwipedActionRunnable != null){
rSwipedActionRunnable.run();
}
}
});
}
}
}
And this is the XML-view of the List-Item:
<?xml version="1.0" encoding="utf-8"?>
<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_width="match_parent"
android:layout_height="#dimen/material_drawer_item_primary">
<LinearLayout
android:id="#+id/swipe_result_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:visibility="visible"
android:paddingEnd="#dimen/material_drawer_vertical_padding"
android:paddingLeft="#dimen/material_drawer_vertical_padding"
android:paddingRight="#dimen/material_drawer_vertical_padding"
android:paddingStart="#dimen/material_drawer_vertical_padding">
<TextView
android:id="#+id/swiped_text"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="center_vertical|start"
android:lines="1"
android:singleLine="true"
android:textDirection="anyRtl"
android:textColor="#android:color/primary_text_dark"
android:textSize="#dimen/material_drawer_item_primary_text"
tools:text="Removed"/>
<TextView
android:id="#+id/swiped_action"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:fontFamily="sans-serif"
android:gravity="center_vertical|start"
android:lines="1"
android:singleLine="true"
android:textDirection="anyRtl"
android:textAllCaps="true"
android:textColor="#android:color/primary_text_dark"
android:textStyle="bold"
android:textSize="#dimen/material_drawer_item_primary_description"
android:text="#string/action_undo"/>
</LinearLayout>
<LinearLayout
android:id="#+id/item_content"
android:layout_width="match_parent"
android:layout_height="#dimen/material_drawer_item_primary"
android:orientation="horizontal"
android:paddingEnd="#dimen/material_drawer_vertical_padding"
android:paddingLeft="#dimen/material_drawer_vertical_padding"
android:paddingRight="#dimen/material_drawer_vertical_padding"
android:paddingStart="#dimen/material_drawer_vertical_padding">
<TextView
android:id="#+id/material_drawer_song"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="12dp"
android:layout_marginLeft="12dp"
android:lines="1"
android:singleLine="true"
android:textSize="#dimen/material_drawer_item_primary_text"
tools:text="Some drawer text" />
<TextView
android:id="#+id/material_drawer_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginLeft="12dp"
android:fontFamily="sans-serif"
android:lines="1"
android:singleLine="true"
android:textSize="#dimen/material_drawer_item_primary_description"
tools:text="Some counter text"
android:layout_weight="1"
android:gravity="center_vertical|start" />
<ImageView
android:id="#+id/material_drawer_minus"
android:layout_width="50dp"
android:layout_height="match_parent"
app:ico_color="#color/md_black_1000"
app:ico_icon="#string/gmd_remove_circle"
app:ico_size="50dp" />
<ImageView
android:id="#+id/material_drawer_plus"
android:layout_width="50dp"
android:layout_height="match_parent"
app:ico_color="#color/md_black_1000"
app:ico_icon="gmd-add_circle"
app:ico_size="50dp" />
</LinearLayout>
</FrameLayout>
</layout>
The part of the code managing the display of the undo button is inside the bindView() method of the ModelItemView.
Please ensure that after swiping the correct item is retrieved via the getItem(position) in the itemSwiped and ensure that the correct item gets notified via notifyItemChanged().
After that ensure that the bindView() is triggered again on that element, and that it has the proper swipeDirection as set via setSwipedDirection(direction).
This is important as:
viewHolder.swipeResultContent.setVisibility(iSwipedDirection != 0 ? View.VISIBLE : View.GONE);
viewHolder.itemContent.setVisibility(iSwipedDirection != 0 ? View.GONE : View.VISIBLE);
Is used to properly adjust the visibility of the views, including showing the undo button.
After several weeks, the answer is simple:
The undo-Button depends on the itemanimator which I always nullified to avoid the blinking. Here is a nice custom animator class that supresses whatever animation you dont want. Now all I had to do was
RecyclerView.setItemAnimator(new CustomItemAnimator());
I want to build a complex layout using recyclerview android. In the layout, I want to have a camera button to the top left fixed and a recyclerview wrapped around it with gallery images. I have checked flexbox layout manager for recyclerview but it doesn't seem to match my use-case.
I want the header to be non-repeating and not to scroll with other items vertically. Here's the layout for the header:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/shareLayout"
android:layout_width="185dp"
android:layout_height="135dp"
android:layout_below="#id/trendingToolbar"
android:background="#color/black">
<ImageView
android:id="#+id/cameraShareIV"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
app:srcCompat="#drawable/camera_white" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/cameraShareIV"
android:layout_centerHorizontal="true">
<TextView
android:id="#+id/infoTxt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginLeft="20dp"
android:gravity="center_horizontal"
android:text="#string/share_pic_video"
android:textColor="#android:color/white"
android:textSize="13sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/infoTxt"
android:layout_marginLeft="16dp"
android:text="#string/share_timeout_txt"
android:textColor="#color/colorPrimaryDark"
android:textSize="11sp"
android:textStyle="bold" />
</RelativeLayout>
and in my activity, here's the XML:
<RelativeLayout 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="base.android.com.thumbsapp.UI.Fragments.TrendingFragment">
<include layout="#layout/trending_toolbar"
android:id="#+id/trendingToolbar"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/trendingRV"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/trendingToolbar"/>
Previously, I had the header inside the activity XML but had no way to wrap a recyclerview around it. So, I have decide to use an adapter like below:
public class TrendingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final String TAG = TrendingAdapter.class.getSimpleName();
private Context context;
private List<Trending> itemList;
private static final int HEADER = 0;
private static final int ITEMS = 1;
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
switch (viewType){
case HEADER:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.trending_header, parent, false);
return new TrendingHeaderViewHolder(v);
case ITEMS:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.trending_items_layout, parent, false);
return new TrendingItemsViewHolder(v);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Trending tr = itemList.get(position);
if (holder instanceof TrendingHeaderViewHolder){
((TrendingHeaderViewHolder) holder).cameraShareIV.setOnClickListener( view -> {
// TODO: 4/2/2018 select image from gallery
});
} else if (holder instanceof TrendingItemsViewHolder){
// TODO: 4/2/2018 populate gallery items here with picasso
}
}
#Override
public int getItemCount() {
return itemList.size();
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
}
I'm confused how to make the header stick and also what to do for getItemViewType method.
Is this the right way to approach this?
Can anyone help out? Thanks.
For this lay out i suggest better option is use this header view
https://github.com/edubarr/header-decor
To make things simple i suggest you to look into this library
In your XML Place RecylerView into StickyHeaderView,choose horizontal or vertical orientation for your RecylerView
<tellh.com.stickyheaderview_rv.StickyHeaderView
android:id="#+id/stickyHeaderView"
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="#android:color/white"
android:scrollbars="vertical" />
</tellh.com.stickyheaderview_rv.StickyHeaderView>
Create data bean class for each item type in RecyclerView. They should extend DataBean. Override the method
public boolean shouldSticky() to decide whether the item view should be suspended on the top.
public class User extends DataBean {
private String login;
private int id;
private String avatar_url;
private boolean shouldSticky;
#Override
public int getItemLayoutId(StickyHeaderViewAdapter adapter) {
return R.layout.item_user;
}
public void setShouldSticky(boolean shouldSticky) {
this.shouldSticky = shouldSticky;
}
// Decide whether the item view should be suspended on the top.
#Override
public boolean shouldSticky() {
return shouldSticky;
}
}
public class ItemHeader extends DataBean {
private String prefix;
#Override
public int getItemLayoutId(StickyHeaderViewAdapter adapter) {
return R.layout.header;
}
#Override
public boolean shouldSticky() {
return true;
}
}
Create ViewBinder to bind different type views with specific data beans. As you see, provideViewHolder(View itemView) corresponds for onCreateViewHolder in RecyclerView, and bindView corresponds for onBindViewHolder in RecyclerView.
public class ItemHeaderViewBinder extends ViewBinder<ItemHeader, ItemHeaderViewBinder.ViewHolder> {
#Override
public ViewHolder provideViewHolder(View itemView) {
return new ViewHolder(itemView);
}
#Override
public void bindView(StickyHeaderViewAdapter adapter, ViewHolder holder, int position, ItemHeader entity) {
holder.tvPrefix.setText(entity.getPrefix());
}
#Override
public int getItemLayoutId(StickyHeaderViewAdapter adapter) {
return R.layout.header;
}
static class ViewHolder extends ViewBinder.ViewHolder {
TextView tvPrefix;
public ViewHolder(View rootView) {
super(rootView);
this.tvPrefix = (TextView) rootView.findViewById(R.id.tv_prefix);
}
}
}
Instantiate StickyHeaderViewAdapter for RecyclerView and register ViewBinders for each item types.
rv = (RecyclerView) findViewById(R.id.recyclerView);
rv.setLayoutManager(new LinearLayoutManager(this));
List<DataBean> userList = new ArrayList<>();
adapter = new StickyHeaderViewAdapter(userList)
.RegisterItemType(new UserItemViewBinder())
.RegisterItemType(new ItemHeaderViewBinder());
rv.setAdapter(adapter);
I have an activity with an AutoCompleteTextView and a button, and below it, a hidden RecyclerView, that starts empty (with no rows).
With the AutoCompleteTextView, I select an object and what I want is, when I click the button, to add that object to the RecyclerView(and turn the visibility on for the recycler).
So far, I've managed to add the object to the recycler's DataSet, but it won't show any row on notifyDataSetChanged().
The layout:
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:id="#+id/ib_add"
android:src="#drawable/ic_add_black"
android:onClick="onAddClick"/>
<AutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/actv_input"
android:layout_toLeftOf="#+id/ib_add"
android:layout_toStartOf="#+id/ib_add"
android:hint="#string/name_hint"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
The Activity (just the relevant functions):
#Bind(R.id.rv) RecyclerView rv;
ArrayList<Ing> ings = new ArrayList<>();
ArrayList<Ing> selectedIngs = new ArrayList<>();
private void setupRecyclers() {
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(new RecyclerViewAdapter(selectedIngs));
}
public void onAddClick(View view) {
Ing ing = ings.get(selectedPosition);
rv.setVisibility(View.VISIBLE);
selectedIngs.add(ing);
((RecyclerViewAdapter)rv.getAdapter()).addIng(ing);
}
The RecyclerViewAdapter:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RViewHolder> {
ArrayList<Ing> ings;
public RecyclerViewAdapter(ArrayList<Ing> ings) {
this.ings = ings;
}
#Override
public RViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View row = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_ing, parent, false);
return new RViewHolder(row);
}
#Override
public void onBindViewHolder(RViewHolder holder, int position) {
Ing ing = ings.get(position);
holder.bindToView(ing);
}
#Override
public int getItemCount() {
return ings.size();
}
public void addIng(Ing ing) {
ings.add(ing);
notifyDataSetChanged();
}
public void setDataSet(ArrayList<Ing> ings) {
this.ings = ings;
notifyDataSetChanged();
}
}
The RecyclerViewHolder:
public class RViewHolder extends RecyclerView.ViewHolder {
Ing ing;
ImageView ivIcon;
TextView tvName;
ImageButton ibRemove;
TextView tvPercentage;
EditText etPercentage;
public RViewHolder(View row) {
super(row);
bindFields(row);
}
private void bindFields(View view) {
ivIcon = (ImageView) view.findViewById(R.id.iv_icon_type);
tvName = (TextView) view.findViewById(R.id.tv_ing);
ibRemove = (ImageButton) view.findViewById(R.id.btn_remove);
tvPercentage = (TextView) view.findViewById(R.id.tv_percentage);
etPercentage = (EditText) view.findViewById(R.id.et_percentage);
}
public void bindToView(Ing ing){
this.ing = ing;
tvName.setText(ing.getName());
ivIcon.setImageResource(R.drawable.icon);
tvName.setVisibility(View.VISIBLE);
ivIcon.setVisibility(View.VISIBLE);
ibRemove.setVisibility(View.VISIBLE);
tvPercentage.setVisibility(View.VISIBLE);
etPercentage.setVisibility(View.VISIBLE);
}
}
What am I missing?
Thanks!
Solved!
The first part, the recycler not showing even with an element inside, was fixed by the 23.2.0 support library's update, that introduced auto measurement for recyclerviews. Before that, if you had a recycler within a relative within a nested, it did some funny business and never initialized the rows inside the recycler.
The second part, the button not adding the row, was because even if you have some onclick event set in your image button, it looks that you have to put android:clickable = true or else it won't work.