I'm new to android programming. I have been trying to make Reminder app that takes Time, Date and Description as Inputs.
I want to add a swipe action to the card. Initially, the Card shows time and date, but when the user swipes on the card, the content in the card must change, it should completely show a new layout which has a TextView containing Description in it.
I have searched everywhere, but all of them have given about removing or moving the card in the RecyclerView.
What I want is, how can I dynamically change the content(or layout) in the card with animation using swipe action?
this is my Card layout card_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout `enter code here`xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="170dp">
<android.support.v7.widget.CardView
android:layout_height="150dp"
android:layout_width="320dp"
android:id="#+id/card_view"
card_view:cardCornerRadius="16dp"
card_view:cardElevation="2dp"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical"
android:background="#color/blue_color">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:fontFamily="sans-serif-light"
android:id="#+id/cardTime"
android:textSize="#dimen/textview_fontsize"
android:textColor="#color/textview_color"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DESCRIPTION"
android:fontFamily="sans-serif-light"
android:id="#+id/description"
android:textSize="#dimen/textview_fontsize"
android:textColor="#color/textview_color"
android:visibility="gone"
/>
<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toEndOf="#+id/cardTime"
android:layout_marginStart="12dp"
android:layout_marginTop="17dp"
android:id="#+id/cardPeriod"
android:textColor="#color/textview_color"
android:fontFamily="sans-serif-light"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/textview_color"
android:layout_alignBottom="#+id/cardTime"
android:id="#+id/time_line" />
<TextView
android:text="09/01/1997"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_marginStart="20dp"
android:id="#+id/cardDate"
android:textColor="#color/textview_color"
android:fontFamily="sans-serif-light"
android:textSize="#dimen/date_fontsize"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
MainActivity.java
public class MainActivity extends AppCompatActivity implements AlarmDialog.AlarmDialogListener {
ArrayList<CardGen> cardsList = new ArrayList<CardGen>();
RecyclerView recyclerView;
CardAdapter cardAdapter = new CardAdapter(cardsList);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.cardList);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(cardAdapter);
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = 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(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
CardAdapter.CardViewHolder holder = (CardAdapter.CardViewHolder) viewHolder;
if (direction == ItemTouchHelper.LEFT){
holder.timeView.setVisibility(View.GONE);
holder.description.setVisibility(View.VISIBLE);
} else {
}
}
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
};
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
}
public void createAlarm(View view){
DialogFragment dialogFragment = new AlarmDialog();
dialogFragment.show(getFragmentManager(), "AlarmDialog");
}
#Override
public void onDialogPositiveClick(DialogFragment dialog) {
Dialog dialog1 = dialog.getDialog();
TimePicker timePicker = (TimePicker) dialog1.findViewById(R.id.timePicker);
int hour = timePicker.getHour();
String tempHour = Integer.toString(hour);
String minute = Integer.toString(timePicker.getMinute());
if(minute.length()==1){minute = "0" + minute;}
Toast.makeText(this, tempHour, Toast.LENGTH_SHORT).show();
System.out.println("this is adapter begin");
CardGen cardGen = new CardGen();
if(hour>12){tempHour = Integer.toString(hour-12);}
else if(hour==0){tempHour="12";}
if(tempHour.length()==1){tempHour = "0"+tempHour;}
cardGen.hour = tempHour+":"+minute;
if(hour>=12){cardGen.period="PM";}else{cardGen.period="AM";}
cardGen.fragmentManager = getFragmentManager();
cardAdapter.addList(cardGen);
System.out.println(Integer.toString(cardsList.size()));
System.out.println("this is the middle");
System.out.println("this is the end");
}
#Override
public void onDialogNegativeClick(DialogFragment dialog) {
}
}
RecyclerAdapter (CardAdapter.java)
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.CardViewHolder> {
private ArrayList<CardGen> cardsList;
public CardAdapter(ArrayList<CardGen> cardsList){
this.cardsList = cardsList;
}
#Override
public int getItemCount() {
return cardsList.size();
}
#Override
public void onBindViewHolder(final CardViewHolder holder, int position) {
final CardGen cardGen = cardsList.get(position);
holder.timeView.setText(cardGen.hour);
holder.periodView.setText(cardGen.period);
final TextView temp = holder.dateView;
holder.dateView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DateSelection newFragment = new DateSelection();
newFragment.setElements(temp);
newFragment.show(cardGen.fragmentManager, "datePicker");
}
});
}
#Override
public CardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cards, parent, false);
return new CardViewHolder(itemView);
}
public void addList(CardGen card){
cardsList.add(card);
notifyItemInserted(cardsList.size());
}
public void removeList(int position){
cardsList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, cardsList.size());
}
public class CardViewHolder extends RecyclerView.ViewHolder{
TextView timeView,periodView,dateView,description;
Button transfer;
public CardViewHolder(View v){
super(v);
timeView = (TextView) v.findViewById(R.id.cardTime);
periodView = (TextView) v.findViewById(R.id.cardPeriod);
dateView = (TextView) v.findViewById(R.id.cardDate);
description = (TextView) v.findViewById(R.id.description);
transfer = (Button) v.findViewById(R.id.transfer);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.bharath.organiserexample.MainActivity">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/cardList">
</android.support.v7.widget.RecyclerView>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="62dp"
android:background="#null"
android:src="#mipmap/add_button"
android:layout_gravity="bottom|right"
android:onClick="createAlarm" />
</FrameLayout>
There are a couple options. The easiest would be to have your cardview contain your description but set the visibility to GONE initially, then when the swipe event happens invert the initial state to GONE and the description to VISIBLE. I would create a helper method to do this. As far as capturing the swipe gesture, take a look at this answer.
Swipe to Dismiss for RecyclerView
You will need to be using a recyclerview but this should work if you put your invert view logic in the onSwiped method
EDIT
To get the cardview, use the ViewHolder from the recyclerview
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
MyCustomViewHolder vh = (MyCustomViewHolder) viewHolder;
if(vh.isDescriptionShown()){
vh.showDetails()
}else {
vh.showDescription()
}
}
Probably you should use a database, then add a swipe listener or (Gesture detector). Whenever the card is swiped you remove the current item from the card and then fetch a new item from the database or list. But I think it'll be best with something like a list, so that you can keep track of the current item. And also be able to easily remove a swiped item. When a user adds an item it is added to your list from the database. That way you don't need to worry about the position of the next item.
Related
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 two RecyclerViews on my screen. And I need to scroll both at the same time on the same distance programmatically. But if I do it fast - the RecyclerViews desynchronizes.
In this source code you should fast click on button in the right top and will see the result.
This is Activity, where button listener for scrolling lists created:
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView1;
private RecyclerView recyclerView2;
private Adapter adapter1;
private Adapter adapter2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView1 = findViewById(R.id.recycler_view1);
recyclerView2 = findViewById(R.id.recycler_view2);
adapter1 = new Adapter();
recyclerView1.setLayoutManager(new LinearLayoutManager(this));
recyclerView1.setAdapter(adapter1);
adapter2 = new Adapter();
recyclerView2.setLayoutManager(new LinearLayoutManager(this));
recyclerView2.setAdapter(adapter2);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
recyclerView1.smoothScrollBy(0, 400);
recyclerView2.smoothScrollBy(0, 400);
}
});
}
}
Adapter for lists:
public class Adapter extends RecyclerView.Adapter<Adapter.Holder>{
private boolean changeHeight = false;
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new Holder(view);
}
#Override
public void onBindViewHolder(Holder holder, int position) {
holder.setContent(String.valueOf(position), position % 2 == 0 ? R.color.colorPrimary : R.color.colorAccent);
if (changeHeight && position == 3) holder.changeHeight();
}
#Override
public int getItemCount() {
return 100;
}
class Holder extends RecyclerView.ViewHolder {
private View view;
private TextView textView;
public Holder(View itemView) {
super(itemView);
view = itemView;
textView = itemView.findViewById(R.id.text_view);
}
public void setContent(String text, int colorRes) {
textView.setText(text);
textView.setBackgroundResource(colorRes);
}
public void changeHeight() {
ViewGroup.LayoutParams params = view.getLayoutParams();
params.height = view.getHeight() * 2;
view.setLayoutParams(params);
}
}
}
This is activity_main.xml layout for Activity
<?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.support.v7.widget.RecyclerView
android:id="#+id/recycler_view1"
android:layout_width="0dp"
android:layout_weight="0.5"
android:layout_height="match_parent"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view2"
android:layout_width="0dp"
android:layout_weight="0.5"
android:layout_height="match_parent"/>
<Button
android:id="#+id/button"
android:layout_width="100dp"
android:layout_height="100dp"/>
</LinearLayout>
Item for RecyclerView item.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="100dp">
<TextView
android:id="#+id/text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"/>
</RelativeLayout>
Crude solution is copying scroll of first recycler into the second one:
recyclerView1.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
recyclerView2.scrollBy(dx, dy);
}
});
Then proceed to smoothScroll only recyclerView1.
I am trying to pick up a single card element kept inside a recycler view and listen to the click and long click events.
However, since you can set the setOnClickListener only on the view, I am finding it difficult to isolate a particular element(card) from the view. As a result, the click event is happening all across the area of the layout.
Please help me isolate a single card from the entire cardview layout and help me write click events to it.
HERE IS MY CODE
CustomAdapter.java
public class CardAdapterLib
extends RecyclerView.Adapter<CardAdapterLib.LibHolder> {
private ArrayList<LibModel> libModel;
public CardAdapterLib(ArrayList<LibModel> data){
this.libModel = data;
}
#Override
public LibHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.recycle_items,parent,false);
// TODO: figure out how to isolate that view
//The listner I have written is getting applied to
the entire layout of R.layout.recycle_items
view.setOnClickListener(LibFragment.myOnClickListener);
return new LibHolder(view);
}
}
My Fragment Class the hosts the recycler view
public class LibFragment extends Fragment {
private static RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private static RecyclerView recyclerView;
private static ArrayList<LibModel> data;
public static View.OnClickListener myOnClickListener;
private static ArrayList<Integer> removedItems;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view=inflater.inflate
(R.layout.fragment_lib_frgment,container,false);
final CoordinatorLayout LibCoordinatorLayout =
(CoordinatorLayout)view.findViewById(R.id.Lib_coordinatorLayout);
myOnClickListener = new MyOnClickListener(getContext());
recyclerView = (RecyclerView) view.findViewById(R.id.library_rv);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
data = new ArrayList<LibModel>();
for (int i = 0; i < myData.titles.length; i++) {
data.add(new LibModel(myData.titles[i],
myData.authors[i],myData.lang[i],myData.id_[i]));
}
removedItems = new ArrayList<Integer>();
adapter = new CardAdapterLib(data);
recyclerView.setAdapter(adapter);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(getActivity(), recyclerView ,
new RecyclerItemClickListener.OnItemClickListener() {
#Override public void onItemClick(View view, int position)
{Toast.makeText(getActivity(),
"SoftPress",Toast.LENGTH_SHORT).show();
// Launch the Requests Fragment here
}
#Override
public void onLongItemClick(View view, int position) {
Toast.makeText(getActivity(),"Hard Press",Toast.LENGTH_SHORT).show();
//Launch the Delete Fragment here
}
})
);
return view;
}
private static class MyOnClickListener implements View.OnClickListener {
private final Context context ;
private MyOnClickListener(Context context) {
this.context = context;
}
#Override
public void onClick(View v) {
// This Toast happens wherever
I click on the R.layout.fragment_lib_frgment area.
// I want to make it happen only when a single card is clicked!
Toast.makeText(context,"Clicked here DA",Toast.LENGTH_SHORT).show();
removeItem(v);
}
private void removeItem(View v) {
int selectedItemPosition = recyclerView.getChildPosition(v);
RecyclerView.ViewHolder viewHolder
= recyclerView.findViewHolderForPosition
(selectedItemPosition);
TextView =(TextView)viewHolder.itemView.
findViewById(R.id.title_card);
String selectedName = (String) titleTV.getText();
int selectedItemId = -1;
for (int i = 0; i < myData.titles.length; i++) {
if (selectedName.equals(myData.titles[i])) {
selectedItemId = myData.id_[i];
}
}
removedItems.add(selectedItemId);
data.remove(selectedItemPosition);
adapter.notifyItemRemoved(selectedItemPosition);
}
}
}
My Layout Files
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:tag="cards main container">
<android.support.v7.widget.CardView
xmlns:card_view="https://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/card_view"
android:layout_margin="5dp"
card_view:cardCornerRadius="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="6">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:layout_weight="1"
android:id="#+id/lib_counter"
android:textSize="120px"
android:padding="10dp"
android:layout_centerInParent="true"
android:gravity="center" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="4"
android:id="#+id/details_holder">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/title_card"
android:layout_margin="5dp"
android:text="Title"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/author_card"
android:layout_margin="5dp"
android:text="Author"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/lang_card"
android:layout_margin="5dp"
android:text="Language"/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
And for the Fragment
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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/Lib_coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.ch330232.pager.Activities.MainActivity">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rvRl"
android:layout_gravity="center_horizontal"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/library_rv"
android:scrollbars="vertical" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
You can separate both clicks in your recycleView Adapter with separating Click listeners for both views as below:
#Override
public YourViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item, viewGroup, false);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.w("Test", "Parent clicked");
}
});
return new YourViewHolder(itemView);
}
#Override
public void onBindViewHolder(YourViewHolder viewHolder, int i) {
viewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.w("Test", "Checkbox clicked");
}
});
}
It is happening every time you click on the fragment because you set it as a click listener for each adapter (or card view) your recycler view has. Use the RecyclerView.addOnItemTouchListener() to activate single items click. Don't add a click listener to every view inside the onBindView method.
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.
I am trying to use the SwipeDismissBehavoir from design support library. I've list items in RecyclerView and swiping an item have to dismiss (like google inbox app) .
I've set the listener for the RecyclerView items but the SwipeDismissBehavior onDismiss listener is not getting called.
SwipeDismissBehavior behavior = new SwipeDismissBehavior();
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams)mItemLayout.getLayoutParams();
params.setBehavior(behavior);
behavior.setListener(new SwipeDismissBehavior.OnDismissListener() {
#Override
public void onDismiss(View view) {
}
#Override
public void onDragStateChanged(int i) {
}
});
mItemLayout.setLayoutParams(params);
Here is example how delete row by swipe
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
// init layout manager
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
final ArrayList<String> list = new ArrayList<String>();
list.add("Item1");
list.add("Item2");
list.add("Item3");
list.add("Item4");
list.add("Item5");
list.add("Item6");
final MyAdapter adapter = new MyAdapter(list);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
ItemTouchHelper swipeToDismissTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
// callback for drag-n-drop, false to skip this feature
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// callback for swipe to dismiss, removing item from data and adapter
list.remove(viewHolder.getAdapterPosition());
adapter.notifyItemRemoved(viewHolder.getAdapterPosition());
}
});
swipeToDismissTouchHelper.attachToRecyclerView(recyclerView);
}
Adapter
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
ArrayList<String> dataset_;
public static class MyViewHolder extends RecyclerView.ViewHolder{
public Button mBtn;
public TextView mTextView2;
public MyViewHolder(View v){
super(v);
mBtn = (Button) itemView.findViewById(R.id.delete);
mTextView2 = (TextView) itemView.findViewById(R.id.textView2);
}
}
public MyAdapter (ArrayList<String> dataset){
dataset_ = dataset;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_text_view,parent,false);
MyViewHolder myViewHolder = new MyViewHolder(v);
return myViewHolder;
}
#Override
public void onBindViewHolder(MyViewHolder holder,int position){
holder.mTextView2.setText(dataset_.get(position));
}
#Override
public int getItemCount(){
return dataset_.size();
}
}
Layout
<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:padding="16dp">
<TextView
style="?android:listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/heading_dismissable_recycler_view" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Item in RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="#+id/textView2"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/delete"
android:text="Delete"
android:layout_marginLeft="150dp"
android:visibility="invisible" />
</LinearLayout>
</LinearLayout>
Tried with single view.
I can know the view was dismissed, but I'm wondering how to restore the view like Gmail.
Layout:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/coordinatorLayout"
tools:context=".MainActivity">
<android.support.v7.widget.CardView
android:id="#+id/cardView"
android:layout_margin="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="Haha"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v7.widget.CardView>
</android.support.design.widget.CoordinatorLayout>
Activity:
public class MainActivity extends AppCompatActivity {
private CoordinatorLayout coordinatorLayout;
private CardView cardView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinatorLayout);
cardView = (CardView) findViewById(R.id.cardView);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) cardView.getLayoutParams();
final SwipeDismissBehavior<CardView> behavior = new SwipeDismissBehavior();
behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END);
behavior.setListener(new SwipeDismissBehavior.OnDismissListener() {
#Override
public void onDismiss(final View view) {
Snackbar.make(coordinatorLayout, "Done", Snackbar.LENGTH_LONG)
.show();
}
#Override
public void onDragStateChanged(int i) {
}
});
params.setBehavior(behavior);
cardView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return behavior.onTouchEvent(coordinatorLayout, cardView, event);
}
});
}
}
I have succeeded implementing the support library SwipeDismissBehavior and it actually requires CoordinatorLayout inside of each inflated card view layout. I haven't noticed any performance issues so far, so I assume CoordinatorLayout is not so heavy for the UI. There is probably a better way, but I still haven't found it.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF0000">
<LinearLayout
android:id="#+id/card_content_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#FFFFFF"
android:padding="20dp">
<TextView
android:id="#+id/card_context_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test text"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
In the constructor of the RecyclerView.ViewHolder implementation class (which is inside the Adapter) I have added:
View cardContentLayout = view.findViewById(R.id.card_content_layout);
SwipeDismissBehavior<View> swipeDismissBehavior = new SwipeDismissBehavior<>();
swipeDismissBehavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_END_TO_START);
swipeDismissBehavior.setListener(new SwipeDismissBehavior.OnDismissListener() {
#Override
public void onDismiss(View view) {
int adapterPosition = getAdapterPosition();
deleteListener.onDismissGesture(view, adapterPosition);
}
#Override
public void onDragStateChanged(int state) { }
});
CoordinatorLayout.LayoutParams coordinatorParams = (CoordinatorLayout.LayoutParams) cardContentLayout.getLayoutParams();
coordinatorParams.setBehavior(swipeDismissBehavior);
cardContentLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return swipeDismissBehavior.onTouchEvent((CoordinatorLayout) itemView, cardContentLayout, event);
}
});