Show RecyclerView in popup window - android

I have a RecyclerView, when RecyclerView item clicked, want to open a popup window which contains another RecyclerView. It is almost done, but in popup window, cardviews don't appear. I can't figure out why, can any one help?
1- My Main RecyclerView Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private ArrayList<Mission> mDataset;
private Context mContext;
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(ArrayList<Mission> myDataset, Context context) {
mDataset = myDataset;
this.mContext = context;
}
// Create new views (invoked by the layout manager)
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(mContext)
.inflate(R.layout.mission_card_item, parent, false);
// set the view's size, margins, paddings and layout parameters
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.mTextView.setText(mDataset.get(position).getName());
holder.mPuanView.setText(mDataset.get(position).getPoint());
holder.mRankView.setText(mDataset.get(position).getRank());
holder.btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext,"Buton Clicked", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return mDataset.size();
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public class MyViewHolder extends RecyclerView.ViewHolder {
public CardView mCardView;
public TextView mTextView;
public TextView mPuanView;
public TextView mRankView;
public Button btnAdd;
public MyViewHolder(final View itemView) {
super(itemView);
mCardView = (CardView) itemView.findViewById(R.id.card_view);
mTextView = (TextView) itemView.findViewById(R.id.tv_text);
mRankView = (TextView) itemView.findViewById(R.id.tv_rank);
mPuanView = (TextView) itemView.findViewById(R.id.tv_puan);
btnAdd = (Button) itemView.findViewById(R.id.button_add);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showPopup();
Toast.makeText(itemView.getContext(),"Element " + getAdapterPosition() + " clicked", Toast.LENGTH_SHORT).show();
Log.d("hello", "Element " + getAdapterPosition() + " clicked.");
}
});
}
}
public void showPopup(){
final View popupView = LayoutInflater.from(mContext).inflate(R.layout.recycler_popup_window, null);
final PopupWindow popupWindow = new PopupWindow(popupView, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
Button btn = (Button) popupView.findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popupWindow.dismiss();
}
});
RecyclerView recyclerView = (RecyclerView) popupView.findViewById(R.id.rv_recycler_view);
ArrayList<String> data = new ArrayList<>();
data.add("my data");
data.add("my test data");
PopupRecyclerViewAdapter adapter = new PopupRecyclerViewAdapter(mContext,data);
recyclerView.setAdapter(adapter);
popupWindow.showAtLocation(popupView,Gravity.CENTER, 0, 0);
}
}
2- My second RecyclerView adapter, its for popup window
public class PopupRecyclerViewAdapter extends RecyclerView.Adapter<PopupRecyclerViewAdapter.MyViewHolder>{
private Context mContext;
private ArrayList<String> data;
public PopupRecyclerViewAdapter(Context mContext, ArrayList<String> data) {
this.mContext = mContext;
this.data = data;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.recycler_popup_card_item, parent,false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.mTextView.setText(data.get(position));
}
#Override
public int getItemCount() {
return data.size();
}
//View Holder
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView mTextView;
public MyViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView.findViewById(R.id.tv_text2);
}
}
}
3- Layout for Recycler popup window
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_recycler_view2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/button"
android:background="#ff4545">
</android.support.v7.widget.RecyclerView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close"
android:id="#+id/button"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
4- CardView Layout for popup RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:id="#+id/card_view"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_margin="10dp"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp"
card_view:elevation="14dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:layout_width="match_parent"
android:layout_height="175dp"
android:id="#+id/imageView2"
android:src="#mipmap/testimage"
android:layout_marginBottom="10dp"
android:scaleType="centerCrop"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tv_text2"
android:text="Blah blah blah..."
android:gravity="center"
android:layout_marginBottom="10dp"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</RelativeLayout>

Add the below lines in your recyclerview popup:
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
recyler_view.setLayoutManager(mLayoutManager);

You may, like me, find this becomes rather a lot of boilerplate code just for a simple Popup Window with a list of clickable items, and so I made a custom Drop Down class which is easily reusable. You just need the PopupWindow custom class, and the RecyclerView adapter, as well as an item data class (in Kotlin), and this is then easily reusable.
The DropDown class:
class DropDown(context: Context, items: List<DropDownItem>, val listener: DropDownClickListener) : PopupWindow(context) {
private val binding = DropdownLayoutBinding.inflate(LayoutInflater.from(context))
init {
contentView = binding.root
setBackgroundDrawable(null)
elevation = 8f
isOutsideTouchable = true
isFocusable = true
binding.recyclerView.adapter = DropDownItemAdapter(items) { item -> onItemClicked(item) }
setOnDismissListener { listener.onMenuDismissed() }
}
private fun onItemClicked(item: DropDownItem) {
listener.onMenuItemClicked(item)
dismiss()
}
fun show(anchor: View) {
showAsDropDown(anchor, 0, 20)
}
interface DropDownClickListener {
fun onMenuItemClicked(item: DropDownItem)
fun onMenuDismissed()
}
}
data class DropDownItem(
val text: String,
val icon: Int
)
With accompanying layout code:
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/rounded_corners"
android:id="#+id/recycler_view"
xmlns:tools="http://schemas.android.com/tools"
tools:listitem="#layout/item_drop_down"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Explanation: This reusable new DropDown class uses ViewBinding of a simple layout that is simply a RecyclerView (with whatever Item layout you want, again mine is a reusable one called item_drop_down, a TextView with a Drawable.)
The constructor just needs three things, the context, the list of drop down items (I made a DropDownItem data class, which for simplicity I put in the same file), and then the listener - an interface also defined in this class).
In the init for this class, we set the content view, setBackgroundDrawable to null to get rid of an ugly border, give it some elevation, then make it dismissable by touching outside or pressing the back button. We then set the recyclerview adapter here from the list of items in the constructor. Finally, we set the on dismiss listener and defer to our interface.
Now the adapter code:
class DropDownItemAdapter(val items: List<DropDownItem>, val clickListener: (DropDownItem) -> Unit) : RecyclerView.Adapter<DropDownItemAdapter.ViewHolder>() {
override fun getItemCount() = items.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(ItemDropDownBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
inner class ViewHolder(val binding: ItemDropDownBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: DropDownItem) {
binding.textView.text = item.text
binding.textView.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(binding.root.context, item.icon), null, null, null)
itemView.setOnClickListener { clickListener(item) }
}
}
}
This is just a straight forward RecyclerView adapter, and rather than another interface, the only thing this needs to notify is when an item is clicked, so simply accept a function parameter in the constructor for handling the clicks.
Altogether, it looks like this in the calling code:
DropDown(view.context, dropDownMenu, this).show(view)
Where dropDownMenu is a list of DropDownItem.
You can then handle the interface functions as desired:
override fun onMenuItemClicked(item: DropDownItem) {
when (item.text) {
"Delete" -> // respond as desired
"Edit" -> // simply inspect the text, or alter your DropDownItem to have an ID
}
}
override fun onMenuDismissed() {
// it may be useful to know when the popup is dismissed
// in my case, I select the item which has been long pressed, and want to know when to un-select it
}
With a nice rounded corners background on my DropDown layout, and being able to know when popup showing and when dismissed to highlight my chosen item, I get this nice effect:

Related

How to do something with focused item of RecyclerView?

I have a simple RecyclerView with only a TextView as each item. By using recyclerView.smoothScrollToPosition(myPosition); in MainActivity, I can scroll to custom item. What I need is changing textColor for current item that is scrolled to, just after scrolling.
For example, if myPosition is 3 and 3rd item of RecyclerView is "current" or "focused", I want to change textColor for this 3rd item.
How can I do that?
MainActivity.java:
public class MainActivity extends AppCompatActivity implements MyAdapter.ItemClickListener {
MyAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> itemTitle_List = new ArrayList<>();
itemTitle_List.add("facebook");
itemTitle_List.add("flickr");
itemTitle_List.add("google_plus");
itemTitle_List.add("instagram");
itemTitle_List.add("linkedin");
itemTitle_List.add("pinterest");
itemTitle_List.add("soundcloud");
itemTitle_List.add("swarm");
itemTitle_List.add("tumblr");
itemTitle_List.add("twitter");
// set up the RecyclerView
RecyclerView recyclerView = findViewById(R.id.recycler_view);
RecyclerView.LayoutManager layoutManager=new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new MyAdapter(this, itemTitle_List);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
recyclerView.smoothScrollToPosition(3);
}
#Override
public void onItemClick(View view, int position) {
//Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
}
}
MyAdapter.java:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<String> itemTitle_List;
private LayoutInflater layoutInflater;
private ItemClickListener itemClickListener;
// data is passed into the constructor
MyAdapter(Context context, List<String> itemTitle_List) {
this.layoutInflater = LayoutInflater.from(context);
this.itemTitle_List = itemTitle_List;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.recyclerview_row, parent, false);
return new ViewHolder(view);
}
// total number of rows
#Override
public int getItemCount() {
return itemTitle_List.size();
}
// binds the title to the TextView, and image to the ImageView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String title = itemTitle_List.get(position);
holder.textView.setText(title);
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView textView;
ViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text_view);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (itemClickListener != null) itemClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
String getItem(int id) {
return itemTitle_List.get(id);
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recycler_view">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
recyclerview_row.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="80dp"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/text_view"
android:layout_gravity="center_vertical"
android:layout_margin="10dp"/>
</LinearLayout>
I found a simple solution, but I'm not sure if this is standard or not.
Add a public integer, named row_index=0 and a public function, in MyAdapter.java, as below:
public void selectRow(int index){
row_index=index;
notifyDataSetChanged();
}
And in the onBindViewHolder function in MyAdapter.java, add this code:
if(position==row_index){
holder.textView.setTextColor(Color.RED);
}
else{
holder.textView.setTextColor(Color.BLACK);
}
Then, after recyclerView.smoothScrollToPosition(3) in MainActivity.java, use this:
MyAdapter.selectRow(3);
MyAdapter.notifyDataSetChanged();
This way, when RecyclerView scrolled to 3rd item, the textColor for this item changes to Red.

Detecting onClick in recycler view using data binding in android

I am Referring to vogella-tutorial for databinding
What i am trying to do: What is the best way to detect onClick in recycler view row for each Item using the dataBinding
activity_second.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="temp"
type="com.vogella.android.databinding.TemperatureData" />
<variable
name="presenter"
type="com.vogella.android.databinding.MainActivityPresenter"/>
</data>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</layout>
rowlayout.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="obj"
type="com.vogella.android.databinding.TemperatureData"
/>
</data>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"
>
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_marginRight="6dip"
android:contentDescription="TODO"
android:src="#drawable/ic_listentry"
/>
<TextView
android:id="#+id/secondLine"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_toRightOf="#id/icon"
android:ellipsize="marquee"
android:text="#{obj.location}"
android:textSize="12sp"
android:maxLines="1"
/>
<TextView
android:id="#+id/firstLine"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#id/secondLine"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_alignWithParentIfMissing="true"
android:layout_toRightOf="#id/icon"
android:gravity="center_vertical"
android:text="#{obj.celsius}"
android:textSize="16sp"
/>
</RelativeLayout>
</layout>
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<TemperatureData> data;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public class MyViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
private final ViewDataBinding binding;
public MyViewHolder(ViewDataBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
public void bind(Object obj) {
binding.setVariable(BR.obj,obj);
binding.executePendingBindings();
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(List<TemperatureData> myDataset) {
data = myDataset;
}
// Create new views (invoked by the layout manager)
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.rowlayout, parent, false);
// set the view's size, margins, paddings and layout parameters
return new MyViewHolder(binding);
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final TemperatureData temperatureData = data.get(position);
holder.bind(temperatureData);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return data.size();
}
}
MyAdapter.java
public class MyAdapter extends MyBaseAdapter {
List<TemperatureData> data;
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(List<TemperatureData> myDataset) {
data = myDataset;
}
#Override
public Object getDataAtPosition(int position) {
return data.get(position);
}
#Override
public int getLayoutIdForType(int viewType) {
return R.layout.rowlayout;
}
#Override
public int getItemCount() {
return data.size();
}
}
Not sure if you have already found a solution, but I managed to do it quite easily.
1) modify onCreateViewHolder method to look like this:
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.rowlayout, parent, false);
MainActivityPresenter presenter = new MainActivityPresenter(this, parent.getContext());
binding.setVariable(BR.presenter,presenter);
// set the view's size, margins, paddings and layout parameters
return new MyViewHolder(binding);
}
2) make MyAdapter to implement MainActivityContract.View so in the end it looks like following:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> implements MainActivityContract.View
3) Implement necessary methods within MyAdapter; e.g:
#Override
public void showData(TemperatureData data) {
String clickedItemCelsius = data.getCelsius();
}
4) Add Presenter variable to your row layout file:
<variable
name="presenter"
type="com.mvvm.ViewModels.MainActivityPresenter"/>
5) Finally hook your onClick event under RelativeLayout:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip"
android:onClick="#{() -> presenter.onShowData(obj)}"
>
Hope it helps!
our viewModel used in recycler view
class UserViewModel (val name: String?, val onClick: () -> Unit)
layout for user_item.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="model"
type="...model.UserViewModel" />
</data>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:onClick="#{()->model.onClick.invoke()}"
android:text="#{model.name}" />
<merge>
creating of models in presenter or modelView or somewhere else
fun loadData() {
// ..
val user = UserViewModel("name") { handleUserEvent() }
.. //
}
fun handleUserEvent() {
// TODO handle on click
}
Probably the most common solution would be to put a click listener on the row layout's root view and call a method on your view model.
For example in rowlayout.xml:
...
<RelativeLayout
android:onClick="#{() -> obj.performClickAction()}"
....
Hey I read that article about a week ago and had the same problem! The article barely mentions how actions should be handled but there is documentation on how to do it. In short, you are going to want a handler.
This handler is defined in your xml
<data>
...
<variable name="handlers" type="com.example.MyHandlers"/>
...
</data>
example usage
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.firstName}"
android:onClick="#{handlers::onClickFriend}"/>
The MyHandlers.java would look like this
public class MyHandlers {
public void onClickFriend(View view) { ... }
}
You would change the add one more line to your MyAdapter.java
public class MyViewHolder extends RecyclerView.ViewHolder {
public void bind(Object obj) {
binding.setVariable(BR.obj,obj);
binding.executePendingBindings();
binding.setHandlers(new MyHandlers());
}
I haven't tested this code but if this doesn't work I can share my adapter .
If other suggestions don't seem to work the way you think it should, take a look at Google Codelab training, specifically "Interacting with RecyclerView items". It's a part of series, but if you are interested in handling the click event in RecyclerView (with Data Binding), you just need to read the aforementioned chapter only.
In short, 1) create a listener class with onClick(), 2) add listener class as data in list item's xml layout file, and 3) use android:onClick="{...}" to map the list item's click event to the listener.
I'm sure there are other ways to achieve the same goal, but this approach seems fairly straightforward.
This way we can use the item click on databinding
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomView> {
List<NewsModel> newsList;
private LayoutInflater layoutInflater;
public CustomAdapter(List<NewsModel> newsList)
{
this.newsList = newsList;
}
#Override
public CustomView onCreateViewHolder(final ViewGroup parent, final int viewType) {
if(layoutInflater == null)
{
layoutInflater = LayoutInflater.from(parent.getContext());
}
final NewsBinding newsBinding = NewsBinding.inflate(layoutInflater,parent,false);
newsBinding.setPresenter(new ClickListener() {
#Override
public void onclickListener() {
Log.d("click me ","click me "+newsBinding.getNewsview().Title);
Toast.makeText(parent.getContext(),""+newsBinding.getNewsview().Title,Toast.LENGTH_LONG).show();
}
});
// View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.innerlayout,parent,false);
return new CustomView(newsBinding);
}
#Override
public void onBindViewHolder(CustomView holder, int position) {
// News news = newsList.get(position);
// holder.title.setText(news.getTitle());
// holder.desc.setText(news.getDesc());
NewsModel newsModel = newsList.get(position);
holder.bind(newsModel);
}
#Override
public int getItemCount() {
return newsList.size();
}
public class CustomView extends RecyclerView.ViewHolder {
private NewsBinding newsBinding;
// TextView title, desc;
public CustomView(NewsBinding newsBinding) {
super(newsBinding.getRoot());
this.newsBinding = newsBinding;
//title = (TextView)itemView.findViewById(R.id.titleval);
//desc =(TextView)itemView.findViewById(R.id.descval);
}
public void bind(NewsModel newsModel)
{
this.newsBinding.setNewsview(newsModel);
}
public NewsBinding getNewsBinding()
{
return newsBinding;
}
}
}
complete project is https://github.com/Vishulucky/DataBinding-MVVM.git
class MyAdapter() :
RecyclerView.Adapter<MyAdapter.MyViewHolder> {
inner class MyViewHolder(private val binding: ItemMyListBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(yourItem: YourItem) {
binding.setVariable(BR.item, yourItem)
binding.executePendingBindings()
binding.animeListCard.setOnClickListener {
onItemClickListener?.let { click ->
click(yourItem)
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding: ItemMyListBinding = DataBindingUtil.inflate(
layoutInflater,
R.layout.item_My_list,
parent,
false
)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(getItem(position))
}
//add these
private var onItemClickListener: (( YourItem) -> Unit)? = null
fun setOnItemClickListener(listener: ( YourItem) -> Unit) {
onItemClickListener = listener
}
}
R.layout.item_My_list layout:
<layout 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">
<data>
<variable
name="item"
type="com.temp.example.data.MyItem" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:orientation="vertical">
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{item.title}"
/>
</LinearLayout>
</layout>
then in your activity :
myAdapter.setOnItemClickListener { item->
//your code here
}

How can I set OnClickListener to two buttons in RecyclerView?

In my android app I have one activity to show a RecyclerView in which each row is composed by a TextView and 2 buttons. Just like that:
Well, following many explanations of internet I have made this Adapter:
public class ListAdapter extends
RecyclerView.Adapter<ListAdapter.ViewHolder> {
private LayoutInflater layoutInflater;
protected Vector<List> lists;
public ListAdapter(Context context, Vector lists) {
layoutInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.lists = lists;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.listadapter, null);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
List list = lists.elementAt(position);
holder.name.setText(list.getName());
//holder.delete.set HOW DO I GET BUTTON HERE?
}
#Override
public int getItemCount() {
return lists.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
public TextView name;
public Button edit;
public Button delete;
public ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.listname);
edit = (Button) itemView.findViewById(R.id.edit);
delete = (Button) itemView.findViewById(R.id.delete);
edit.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.edit:
break;
case R.id.delete:
break;
default:
break;
}
}
}
}
I haven't found examples of having 2 buttons (there are only examples of adding images) in each view of the recyclerview, as in the first image. I mean, guess I have 10 List elements in my RecyclerView, how can I have in each of them to one side a TextView with the name of the List and 2 buttons and handle clickListener?. As in the following image, which I have done by hand for you to see what I am talking about:
This is the activity that will show the recyclerView; don't take it into account because I am pretty sure the way is wrong. I get lists information from sqlite database:
public class ShowListOfLists extends AppCompatActivity {
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_list_of_lists);
LocalDB localDB = new LocalDB(this, "localBD", null, 1);
Vector <List> ListAdapter = localDB.getAllPrivateList();
recyclerView = (RecyclerView) findViewById(R.id.recyclerviewlistas);
recyclerView.setAdapter(new ListAdapter(this, ListAdapter));
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
}
A list have the following attributes:
-idList int
-name String
-Description String
-creationDate Date
-active int (0 or 1)
-deactivationDate Date
Thank you in advance.
/*******************************EDIT****************************************/
Thank to you I have been able to show the recyclerView and it works well. But I see that:
Instead of that:
This the XML code and design of the adapter:
<?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="60dp"
android:background="#drawable/rectangle_bg"
android:orientation="horizontal"
android:weightSum="1"
android:layout_marginTop="5dp">
<TextView
android:id="#+id/listname"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_weight="0.75"
android:gravity="center_vertical"
android:text="TextView"
android:textSize="15sp"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.25"
android:gravity="end"
android:orientation="vertical">
<ImageButton
android:id="#+id/delete"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="#android:color/transparent"
android:contentDescription="Delete"
app:srcCompat="#android:drawable/ic_menu_delete" />
<ImageButton
android:id="#+id/edit"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="#android:color/transparent"
android:contentDescription="Edit"
app:srcCompat="#android:drawable/ic_menu_edit" />
</LinearLayout>
</LinearLayout>
And this is the XML of the recyclerview
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="match_parent"
tools:context="com.pc.kanayel.runoutof.ShowListOfLists"
android:orientation="vertical"
android:id="#+id/recyclerviewlistas">
</android.support.v7.widget.RecyclerView>
You just need to add some code to your ListAdapter. It is there, where you have to implement onClickListener. The code for your case should look something like the one below.
You can pass any parameter you need to. It depends on the functionality you want to achieve. Here I have demonstrated passing the order of item clicked inside of list.
Option 1 (power/performance efficient)
So, what does the code below actually mean? You have already created a ViewHolder and implemented OnClickListener. That is correct. Now you need to set OnClickListener to two buttons. But what these buttons will do when clicked is defined by the interface we created inside of ViewHolder.
When app will run RecyclerView will create as many ViewHolders as it is needs to fill the available screen with list items by calling onCreateViewHolder() method for each of viewholders. When you scroll up/down these ViewHolders will be reused. OnCreateViewHolder() is not called, only onBindViewHolder() is called to update the content of viewholder. The code below made so that, when ViewHolder is created it will also create an MyClickListener that will be used by OnClickListener of viewholder and when viewholder is reused it will not create new OnClickListener. It means that our method is performance efficient.
Option 2 (not efficient)
You could also setOnClickListener() inside of onBindViewHolder(). However, as I have mentioned in the paragraph above, this method is called every time you scroll to update the content of viewholder. Now it would create new OnClickListener object everytime. While Option 1 has OnClickListener on every ViewHolder and it reuses them.
Code for Option 1
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {
private LayoutInflater layoutInflater;
protected Vector<List> lists;
public ListAdapter(Context context, Vector lists) {
layoutInflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.lists = lists;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.listadapter, null);
ViewHolder holder = new ViewHolder(view, new MyClickListener() {
#Override
public void onEdit(int p) {
// Implement your functionality for onEdit here
}
#Override
public void onDelete(int p) {
// Implement your functionality for onDelete here
}
});
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
List list = lists.elementAt(position);
holder.name.setText(list.getName());
}
#Override
public int getItemCount() {
return lists.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
MyClickListener listener;
TextView name;
Button edit;
Button delete;
public ViewHolder(View itemView, MyClickListener listener) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.listname);
edit = (Button) itemView.findViewById(R.id.edit);
delete = (Button) itemView.findViewById(R.id.delete);
this.listener = listener;
edit.setOnClickListener(this);
delete.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.edit:
listener.onEdit(this.getLayoutPosition());
break;
case R.id.delete:
listener.onDelete(this.getLayoutPosition());
break;
default:
break;
}
}
}
public interface MyClickListener {
void onEdit(int p);
void onDelete(int p);
}
}
Edit for your second question
To make list items take all the width set the width of your recyclerview to match_parent. It is also better to make it a child view of some layout. For instance as given below.
<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="com.pc.kanayel.runoutof.ShowListOfLists">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerviewlistas"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<RelativeLayout>
And change this code inside of your adapter:
View view = layoutInflater.inflate(R.layout.listadapter, null);
to this:
View view = layoutInflater.inflate(R.layout.listadapter, parent, false);
You can do simply like this:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
List list = lists.elementAt(position);
holder.name.setText(list.getName());
holder.edit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do your stuff
}
});
holder.delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do your stuff
}
});
}

Create curved layout for Android Wearable Recycler View

I am trying to create a curved Wearable Recycler view similar to the one given in below link: https://developer.android.com/training/wearables/ui/lists.html
But I don't see curved layout and all the text comes in a single line .
Can anyone help me how to create a curved Wearable Recycler view . The below is the code fragment. Please let me know if something went wrong in the below code:
My Layout is below:
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.WearableRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/menu_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
>
</android.support.wearable.view.WearableRecyclerView>
In my fragment I am using the below code for curved layout:
InformationAdapter informationAdapter = new InformationAdapter(dataSet, images,MenuActivity.this );<br>
wearableRecyclerView.setAdapter(informationAdapter); <br>
wearableRecyclerView.setCenterEdgeItems(true);<br>
wearableRecyclerView.setLayoutManager(new CurvedChildLayoutManager(getActivity()));<br>
wearableRecyclerView.setCircularScrollingGestureEnabled(true);
wearableRecyclerView.setBezelWidth(0.5f);
wearableRecyclerView.setScrollDegreesPerScreen(90);
My Adapter is as below:
public class InformationAdapter extends
WearableRecyclerView.Adapter<InformationAdapter.ViewHolder> {
private static final String TAG = "CustomRecyclerAdapter";
private String[] mDataSet;
private int[] mImages;
private ItemClickListener itemClickListener;
// Custom Controller used to instruct main activity to update {#link Notification} and/or
// UI for item selected.
public static class ViewHolder extends WearableRecyclerView.ViewHolder {
private final TextView mTextView;
private final ImageView menuImageIcon;
public ViewHolder(View view) {
super(view);
mTextView = (TextView) view.findViewById(R.id.textView);
menuImageIcon = (ImageView)view.findViewById(R.id.menu_image);
}
#Override
public String toString() { return (String) mTextView.getText(); }
}
public InformationAdapter(String[] dataSet,int[] mImages,ItemClickListener itemClickListener) {
mDataSet = dataSet;
this.mImages = mImages;
this.itemClickListener = itemClickListener;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.recycler_row_item, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
Log.d(TAG, "Element " + position + " set.");
viewHolder.mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// mController.itemSelected(mDataSet[position]);
itemClickListener.onItemSelected(mDataSet[position]);
}
});
// Replaces content of view with correct element from data set
viewHolder.mTextView.setText(mDataSet[position]);
viewHolder.menuImageIcon.setImageResource(mImages[position]);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return mDataSet.length;
}
}
Row Item layout for Adapter:
<?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:layout_gravity="center"
android:paddingTop="#dimen/recycler_row_padding"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#drawable/ic_n_white_48dp"
android:id="#+id/menu_image"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:textSize="#dimen/recycler_row_text_size"
android:id="#+id/textView"
/>
</LinearLayout>
I faced with the same problem. Changing
android:layout_height="wrap_content"
to
android:layout_height="match_parent"
in WearableRecyclerView worked for me. Hope it helps.

Implementing an RecycleView or CardView items with the same design for eachother

I need to know, when the user clicking on one item(or for example, whatsApp contacts) WhatsApp showing to the user one design with this picture example:
here is the recycle view items:
and i'm using :
http://code.tutsplus.com/tutorials/getting-started-with-recyclerview-and-cardview-on-android--cms-23465
Main-activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView rv = (RecyclerView)findViewById(R.id.rv);
rv.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(context);
rv.setLayoutManager(llm);
RVAdapter adapter = new RVAdapter(persons);
rv.setAdapter(adapter);
}
}
Mainactivity Xml layout:
<?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:padding="16dp"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/person_photo"
android:src="#mipmap/ic_launcher"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginRight="16dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/person_name"
android:layout_toRightOf="#+id/person_photo"
android:layout_alignParentTop="true"
android:textSize="30sp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/person_age"
android:layout_toRightOf="#+id/person_photo"
android:layout_below="#+id/person_name"
/>
</RelativeLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rv"/>
</LinearLayout>
here is the Adaptor:
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder>{
#Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.activity_main, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
personViewHolder.personName.setText(persons.get(i).name);
personViewHolder.personAge.setText(persons.get(i).age);
personViewHolder.personPhoto.setImageResource(persons.get(i).photoId);
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public int getItemCount() {
return persons.size();
}
List<Person> persons;
RVAdapter(List<Person> persons){
this.persons = persons;
}
public static class PersonViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView personName;
TextView personAge;
ImageView personPhoto;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
personName = (TextView)itemView.findViewById(R.id.person_name);
personAge = (TextView)itemView.findViewById(R.id.person_age);
personPhoto = (ImageView)itemView.findViewById(R.id.person_photo);
}
}
}
currently, there is an error in MainActivity Java codes:
cannot resolve symbol Contect and also for Person!
So, after this (i hope this fixed).
I need to when user clicked on the each item, It showing to us similar design, But, With names for each item.
Example: user clicked on item 2: Lavery Maiss
and then goto another activity or layout and show us this name.
and if user clicked on the item 1: Emma Wilson it show us in another activity same design for each item, But, with Emma Wilson name.
What should i do and what's wrong with my codes?
what we can do for showing this ?
Cheers!
After researching about this, i found a good tutorial which is no one mention it.
https://github.com/tarek360/Material-Animation-Samples
So, We need a Adaptor for doing this like below:
public class BlogRecyclerAdapter extends
RecyclerView.Adapter<BlogRecyclerAdapter.SimpleItemViewHolder> {
private List<Blog> items;
// Provide a reference to the views for each data item
// Provide access to all the views for a data item in a view holder
public final static class SimpleItemViewHolder extends RecyclerView.ViewHolder {
ImageView image;
TextView title;
TextView subTitle;
CardView cardView;
public SimpleItemViewHolder(View itemView) {
super(itemView);
image = (ImageView) itemView.findViewById(R.id.imageThumb);
title = (TextView) itemView.findViewById(R.id.title);
subTitle = (TextView) itemView.findViewById(R.id.subTitle);
cardView = (CardView) itemView.findViewById(R.id.cardView);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public BlogRecyclerAdapter(List<Blog> items) {
this.items = items;
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return this.items.size();
}
// Create new items (invoked by the layout manager)
// Usually involves inflating a layout from XML and returning the holder
#Override
public SimpleItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View itemView = LayoutInflater.from(viewGroup.getContext()).
inflate(R.layout.blog_item, viewGroup, false);
return new SimpleItemViewHolder(itemView);
}
// Replace the contents of a view (invoked by the layout manager)
// Involves populating data into the item through holder
#Override
public void onBindViewHolder(SimpleItemViewHolder viewHolder, int position) {
viewHolder.image.setImageResource(items.get(position).getImageRes());
viewHolder.image.setTag(position);
viewHolder.title.setText(items.get(position).getTitle());
viewHolder.subTitle.setText(items.get(position).getSubTitle());
viewHolder.cardView.setCardBackgroundColor(items.get(position).getBackGroundColor());
}
}
Take a look at these codes:
// Replace the contents of a view (invoked by the layout manager)
// Involves populating data into the item through holder
#Override
public void onBindViewHolder(SimpleItemViewHolder viewHolder, int position) {
viewHolder.image.setImageResource(items.get(position).getImageRes());
viewHolder.image.setTag(position);
viewHolder.title.setText(items.get(position).getTitle());
viewHolder.subTitle.setText(items.get(position).getSubTitle());
viewHolder.cardView.setCardBackgroundColor(items.get(position).getBackGroundColor());
}
Here is a good example for doing this with Animation:
https://github.com/tarek360/Material-Animation-Samples/tree/master/app/src/main/java/com/tarek360/animationsamples
exactly what we need ;)

Categories

Resources