I'm developing a screen for an android app where I need to add a click event to each row of recyclerview and it's working in parts.
The problem is that once the intent is loaded the clickable area is limited to the width of its the contents.
the clickable area works fine (at 100% width) only if the recyclerview row is completely hidden from the viewport after a scroll happen.
Bellow has a gif that illustrates my problem. Note that before scroll the clickable area is reduced to row content and after scroll the clickable area fills the row.
<img src="https://i.imgur.com/wGvqa5Z.gif" width="150" style="width:150px; border:1px solid #000;" />
active_catalog.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="viniciusdesouza.com.br.barbearia.CatalogActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_catalog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_catalog" />
</android.support.design.widget.CoordinatorLayout>
content_catalog.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="viniciusdesouza.com.br.barbearia.CatalogActivity"
tools:showIn="#layout/activity_catalog">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_catalog_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
catalog_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="72sp"
android:gravity="center_vertical"
android:orientation="vertical"
android:background="?android:attr/selectableItemBackground">
<TextView
android:id="#+id/txt_catalog_item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="TextView"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="#+id/txt_catalog_item_price"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="TextView" />
</LinearLayout>
CatalogAdapter.java
public class CatalogAdapter extends RecyclerView.Adapter<CatalogAdapter.ViewHolderCatalog> {
private List<CatalogItem> catalog;
private OnRecyclerViewItemClickListener listener;
public CatalogAdapter (List<CatalogItem> catalog) {
this.catalog = catalog;
}
#Override
public CatalogAdapter.ViewHolderCatalog onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.catalog_item, parent, false);
ViewHolderCatalog viewHolderCatalog = new ViewHolderCatalog(view);
return viewHolderCatalog;
}
#Override
public void onBindViewHolder(CatalogAdapter.ViewHolderCatalog holder, final int position) {
if ( (catalog != null) && (catalog.size() > 0)) {
CatalogItem item = catalog.get(position);
holder.txtItemName.setText(item.name);
holder.txtItemPrice.setText(String.valueOf(item.price));
holder.itemView.setOnClickListener(new View.OnClickListener () {
#Override
public void onClick(View v){
listener.onRecyclerViewItemClicked(position, -1);
}
});
}
}
#Override
public int getItemCount() {
return catalog.size();
}
public static class ViewHolderCatalog extends RecyclerView.ViewHolder {
public TextView txtItemName;
public TextView txtItemPrice;
public ViewHolderCatalog(View itemView) {
super(itemView);
txtItemName = (TextView) itemView.findViewById(R.id.txt_catalog_item_name);
txtItemPrice = (TextView) itemView.findViewById(R.id.txt_catalog_item_price);
}
}
/**
* Custom created method for Setting the item click listener for the items and items with in items
* #param listener OnRecyclerViewItemClickListener
*/
public void setOnItemClickListener(OnRecyclerViewItemClickListener listener)
{
this.listener = listener;
}
}
CatalogActivity.java
public class CatalogActivity extends AppCompatActivity implements OnRecyclerViewItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catalog);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_catalog);
setSupportActionBar(toolbar);
// back button
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
recyclerViewCatalog = (RecyclerView) findViewById(R.id.rv_catalog_list);
recyclerViewCatalog.setHasFixedSize(true);
dbConnect();
catalogRepository = new CatalogRepository(databaseHandler);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
catalog = catalogRepository.all();
recyclerViewCatalog.setLayoutManager(linearLayoutManager);
catalogAdapter = new CatalogAdapter(catalog);
mDividerItemDecoration = new DividerItemDecoration(
recyclerViewCatalog.getContext(),
linearLayoutManager.getOrientation()
);
recyclerViewCatalog.addItemDecoration(mDividerItemDecoration);
recyclerViewCatalog.setAdapter(catalogAdapter);
catalogAdapter.setOnItemClickListener(this);
}
#Override
public void onRecyclerViewItemClicked(int position, int id)
{
// do something with item clicked
}
}
Any help will be appreciated
The issue has to do with your ConstraintLayout in your content_catalog.xml file.
A similar issue is happening here, so to fix it, try simply replacing it with something else like a LinearLayout or RelativeLayout and it should resolve the issue of the view not expanding until after scrolling re-renders it.
Just change your ViewHolderCatalog class like below
public static class ViewHolderCatalog extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView txtItemName;
public TextView txtItemPrice;
public ViewHolderCatalog(View itemView) {
super(itemView);
txtItemName = (TextView) itemView.findViewById(R.id.txt_catalog_item_name);
txtItemPrice = (TextView) itemView.findViewById(R.id.txt_catalog_item_price);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), “You clicked your your recycler view item”, Toast.LENGTH_SHORT).show();
}
}
Related
I have an app that would benefit from a recyclerView nested in a recyclerView.
The issue I have though is that when I remove a textView outside on the recyclerView, the inner recyclerView doesn't redraw itself.
My app allows the user to read pages (RecyclerView with multiple paragraphs (nested RecyclerView)
The user can click the chapter title to get some added definitions/context displayed and if he clicks the definition it goes away.
The issue is when the definition goes away the nested RecyclerView doesn't redraw/re-size itself without a page swipe back and forth, could this be resolved?
I'm not android expert so I'm probably doing something wrong :S
My 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">
<LinearLayout
android:id="#+id/pageContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_alignParentTop="true"
android:layout_above="#+id/definitionContainer">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/page"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"/>
</LinearLayout>
<RelativeLayout
android:id="#+id/definitionContainer"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="120dp"
android:visibility="gone"
android:onClick="hideDefinition">
<View android:id="#+id/devider" android:layout_marginTop="1dp" android:layout_marginBottom="1dp" android:background="#color/colorAccent" android:layout_width="match_parent" android:layout_height="2px" android:layout_alignParentTop="true"/>
<ScrollView
android:id="#+id/definitionScrollView"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:layout_below="#+id/devider"
android:background="#color/colorPrimaryDark"
android:onClick="hideDefinition">
<TextView
android:id="#+id/definitionTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:text="Lorem ipsum dolor sit amet, ..."
android:onClick="hideDefinition" />
</ScrollView>
</RelativeLayout>
</RelativeLayout>
My MainActivity.java
public class MainActivity extends AppCompatActivity {
#BindView(R.id.page) RecyclerView page;
#BindView(R.id.definitionContainer) RelativeLayout definitionContainer;
private ChapterContainerAdapter chapterAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
//if (page == null) page = findViewById(R.id.page);
page.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
page.setItemAnimator(new DefaultItemAnimator());
chapterAdapter = new ChapterContainerAdapter(this);
page.setAdapter(chapterAdapter);
SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(page);
}
public void showDefinition (View v) {
definitionContainer.setVisibility(View.VISIBLE);
}
public void hideDefinition (View v) {
definitionContainer.setVisibility(View.GONE);
}
}
My recyclerView Adapter is very basic:
public class ChapterContainerAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private Context ctx;
static final String pageData[] = {"Page 1", "Page 2", "Page 3", "Page 4", "Page 5"};
public ChapterContainerAdapter(Context ctxIn) { ctx = ctxIn; }
#Override public void onBindViewHolder(BaseViewHolder holder, int position) { holder.onBind(position); }
#Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ChapterContainerAdapter.ChapterAdapterViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_page, parent, false));
}
#Override public int getItemCount() { return pageData.length; }
public class ChapterAdapterViewHolder extends BaseViewHolder {
#BindView(R.id.chapterTitle)
TextView chapterTitle;
#BindView(R.id.chapterContentRecyclerView)
RecyclerView chapterContentRecyclerView;
ParagraphAdapter paragraphAdapter;
public ChapterAdapterViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
protected void clear() { chapterTitle.setText(""); }
public void onBind(int position) {
super.onBind(position);
initiateVerseRecyclerView(position);
}
private void initiateVerseRecyclerView (int position) {
chapterTitle.setText(pageData[position]);
chapterContentRecyclerView.setLayoutManager(new LinearLayoutManager(ctx, RecyclerView.VERTICAL, false));
chapterContentRecyclerView.setItemAnimator(new DefaultItemAnimator());
paragraphAdapter = new ParagraphAdapter(ctx, position);
chapterContentRecyclerView.setAdapter(paragraphAdapter);
}
}
}
Did you to call notifyDataSetChange manually on adapter after removing view?
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 a RecyclerView to show some images loaded by Picasso. As they have different aspect ratios, I'm using a StaggeredGridLayoutManager. Everything looks good, but when scrolling and a new image shows up, images move up or down a little, like they are getting been relocated. They dont stay in the same place.
The thing is, if I use a GridLayout, everything works perfectly, looks like having different item's sizes messes it up.
This is the ActivityMain class:
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Especificamos el layout 'products_grid.xml'
setContentView(R.layout.products_grid);
_initData();
_initAuxViews();
_initToolbar();
_initNavigationDrawers();
_initAnimations();
new ConnectToServer().execute();
}
protected void _initRecyclerView()
{
mProductsRecyclerView = (RecyclerView)findViewById(R.id.grid_recycler);
mStaggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mProductAdapter = new ProductsGridAdapter(this, mProductsDisplayedList);
mProductsRecyclerView.setLayoutManager(mStaggeredGridLayoutManager);
mProductsRecyclerView.setAdapter(mProductAdapter);
mProductsRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener()
{
...
}
}
main.xml, I have a custom RecyclerView, but this does not affect, I checked 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:id="#+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/shop_background_bw">
<!-- Contenido principal -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Recylcer Grid -->
<com.wallakoala.wallakoala.Views.GridRecyclerView
android:id="#+id/grid_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
android:clipToPadding="false"
android:paddingTop="?attr/actionBarSize"
android:layoutAnimation="#anim/grid_layout_animation"/>
<!-- Toolbar -->
<include android:id="#+id/appbar"
layout="#layout/toolbar">
</include>
<!-- Loading View -->
<com.wang.avi.AVLoadingIndicatorView
android:id="#+id/avloadingIndicatorView"
android:layout_width="125dp"
android:layout_height="125dp"
android:layout_gravity="center"
android:visibility="gone"
app:indicator="BallClipRotate"
app:indicator_color="#color/colorAccent"/>
<!-- Texto de no prductos -->
<TextView
android:id="#+id/nodata_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/action_bar_height"
android:layout_gravity="center_horizontal"
android:visibility="gone"
android:paddingTop="#dimen/action_bar_height"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="#string/nodata_message"
android:textSize="20sp"
android:textColor="#color/colorText"/>
</FrameLayout>
<include layout="#layout/left_navigation_drawer"/>
</android.support.v4.widget.DrawerLayout>
</android.support.design.widget.CoordinatorLayout>
item_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardPreventCornerOverlap="false"
app:cardElevation="4dp"
app:cardCornerRadius="4dp"
app:cardUseCompatPadding="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Loading View -->
<com.wang.avi.AVLoadingIndicatorView
android:id="#+id/avloadingitem"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:visibility="gone"
app:indicator="BallClipRotate"
app:indicator_color="#color/colorAccent"/>
<!-- Background-->
<com.makeramen.roundedimageview.RoundedImageView
android:id="#+id/grid_background"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#color/colorText"
android:alpha="0.2"
android:visibility="gone"
app:riv_corner_radius_bottom_left="4dp"
app:riv_corner_radius_bottom_right="4dp"
app:riv_corner_radius_top_left="4dp"
app:riv_corner_radius_top_right="4dp"/>
<!-- Main Image-->
<com.makeramen.roundedimageview.RoundedImageView
android:id="#+id/grid_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
app:riv_corner_radius_bottom_left="4dp"
app:riv_corner_radius_bottom_right="4dp"
app:riv_corner_radius_top_left="4dp"
app:riv_corner_radius_top_right="4dp"/>
<!-- Footer -->
<RelativeLayout
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:alpha="0.75">
<!-- Info extra -->
<include android:id="#+id/extraInfo"
layout="#layout/product_footer_extra"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"/>
<!-- Info principal -->
<include android:id="#+id/mainFooter"
layout="#layout/product_footer"
android:layout_height="#dimen/footer_height"
android:layout_width="match_parent"
android:layout_below="#id/extraInfo"/>
</RelativeLayout>
</FrameLayout>
</android.support.v7.widget.CardView>
EDIT: Adapter code:
public class ProductsGridAdapter extends RecyclerView.Adapter<ProductsGridAdapter.ProductHolder>
{
/* Constants */
private static final String TAG = "CUOKA";
private static final String PACKAGE = "com.wallakoala.wallakoala";
/* Context */
private static Context mContext;
/* Data */
private static List<Product> mProductList;
public static class ProductHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private Product mProduct;
private ImageButton mFavImageButton;
private ImageView mProductImageView;
private ImageView mErrorImageView;
private View mLoadingView;
private View mBackgroundView;
private View mProductFooterView, mProductFooterExtraView, mProductFooterMainView;
private TextView mTitleTextView, mSubtitleTextView, mNameTextView, mPriceTextView;
private Animation scaleUpFooterExtra, scaleDownFooterExtra;
public ProductHolder(View itemView)
{
super(itemView);
mErrorImageView = (ImageView)itemView.findViewById(R.id.broken_image);
mTitleTextView = (TextView)itemView.findViewById(R.id.footer_title);
mSubtitleTextView = (TextView)itemView.findViewById(R.id.footer_subtitle);
mProductImageView = (ImageView)itemView.findViewById(R.id.grid_image);
mFavImageButton = (ImageButton)itemView.findViewById(R.id.footer_fav_button);
mNameTextView = (TextView)itemView.findViewById(R.id.name);
mPriceTextView = (TextView)itemView.findViewById(R.id.price);
mBackgroundView = itemView.findViewById(R.id.grid_background);
mLoadingView = itemView.findViewById(R.id.avloadingitem);
mProductFooterView = itemView.findViewById(R.id.footer);
mProductFooterExtraView = itemView.findViewById(R.id.extraInfo);
mProductFooterMainView = itemView.findViewById(R.id.mainFooter);
mProductFooterView.setOnClickListener(this);
//mProductImageView.setOnClickListener(this);
scaleUpFooterExtra = AnimationUtils.loadAnimation(mContext, R.anim.scale_up);
scaleDownFooterExtra = AnimationUtils.loadAnimation(mContext, R.anim.scale_down);
}
public void bindProduct(Product product)
{
/* Inicializamos los TextViews */
mTitleTextView.setText(product.getShop());
mSubtitleTextView.setText(product.getColors().get(0).getReference());
mNameTextView.setText(product.getName());
mPriceTextView.setText(String.format("%.2f", product.getPrice()) + "€");
/* Ocultamos la info, IMPORTANTE. Cosas malas pasan si no se pone. Tambien la imagen de error. */
mProductFooterExtraView.setVisibility(View.GONE);
mProductFooterMainView.setVisibility(View.GONE);
mErrorImageView.setVisibility(View.GONE);
/* Mostramos la view de carga y el background */
mLoadingView.setVisibility(View.VISIBLE);
mBackgroundView.setVisibility(View.VISIBLE);
/* Ponemos el icono del corazon. */
mFavImageButton.setBackgroundResource(R.drawable.ic_favorite_border_white);
/* Cargamos la imagen usando Picasso */
String url = product.getColors().get(0).getImages().get(0).getPath().replaceAll(".jpg", "_Small.jpg");
Picasso.with(mContext)
.load(url)
.into(mProductImageView, new Callback() {
#Override
public void onSuccess() {
mBackgroundView.setVisibility(View.GONE);
mLoadingView.setVisibility(View.GONE);
mProductFooterMainView.setVisibility(View.VISIBLE);
}
#Override
public void onError() {
mLoadingView.setVisibility(View.GONE);
mErrorImageView.setVisibility(View.VISIBLE);
}
});
mProduct = product;
}
public ProductsGridAdapter(Context context, List<Product> productList)
{
mContext = context;
mProductList = productList;
}
public void updateProductList(List<Product> productList)
{
mProductList = productList;
}
#Override
public ProductHolder onCreateViewHolder(ViewGroup viewGroup, int viewType)
{
View itemView = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.product_item_grid
, viewGroup
, false );
return new ProductHolder(itemView);
}
#Override
public void onBindViewHolder(final ProductHolder productHolder, int pos)
{
productHolder.bindProduct(mProductList.get(pos));
}
#Override
public int getItemCount()
{
return mProductList.size();
}
}
EDIT 2: I've found out what's going on. The cardview is firstly created without the image, when it's loaded, the layout is redrawn, therefore the weird movement produced. I tried to do this:
WHen the image is first loaded, I save the height of it, and when the recyclerView is scrolled up, I set the background image of the cardview with the height already saved so it has the same dimensions as the image, and this should do the trick. But it doesnt. This is what I tried, this code belongs to the Holder constructor in the Adapter.
final ViewTreeObserver mProductImageViewTreeObserver = mProductImageView.getViewTreeObserver();
final ViewTreeObserver mBackgroundTreeObserver = mBackgroundView.getViewTreeObserver();
mProductImageViewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
if (mProductHeight != mProductImageView.getHeight())
{
mProductHeight = mProductImageView.getHeight();
}
}
});
mBackgroundTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
#Override
public boolean onPreDraw()
{
if((mProductHeight > 0) && (mProductHeight != mBackgroundView.getHeight()))
{
mBackgroundView.getLayoutParams().height = mProductHeight;
}
return true;
}
});
Does anyone have a clue of what's wrong?
Thanks in advance,
I found the solution myself. The trick is to save the aspect ratio when loading the image for the first time into a Target object.
Then, in the OnPrepareLoad, check if this image has been loaded previously. If so, use the aspect ratio stored to set the final height, this way, there's no readjustment and the scroll works smoothly.
mTarget = new Target()
{
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
{
mLoadingView.setVisibility(View.GONE);
mProductFooterMainView.setVisibility(View.VISIBLE);
mProductImageView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
mProductImageView.setBackgroundColor(-1);
mProductImageView.setAlpha(1.0f);
if (mProductBitmapArray[position] == 0.0f)
mProductBitmapArray[position] = (double)bitmap.getHeight() / (double)bitmap.getWidth();
mProductImageView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable)
{
... do stuff
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable)
{
mProductImageView.setImageBitmap(null);
if (mProductBitmapArray[position] != 0)
mProductImageView.getLayoutParams().height = (int)(mProductImageView.getWidth()
* mProductBitmapArray[position]);
else
mProductImageView.getLayoutParams().height = 600;
mProductImageView.setBackgroundColor(mContext.getResources().getColor(R.color.colorText));
mProductImageView.setAlpha(0.1f);
}
};
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);
}
});
I m trying to display nested recyclerview but the child items does not display.
I want to display different items in all child view.
I don't get a error, but the view is not refreshed.
Here is my code can any one help.
Thanks
public class MainActivity extends ActionBarActivity {
RecyclerView recyclerView;
RootAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter = new RootAdapter(this);
recyclerView = (RecyclerView) findViewById(R.id.recyclerRoot);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
}
private class RootAdapter extends RecyclerView.Adapter<RootAdapter.RootViewHolder> {
private final LayoutInflater inflater;
String[] _items = new String[]{"ITEM 1", "ITEM 2", "ITEM 3", "ITEM 4"};
public RootAdapter(Context context)
{
inflater = LayoutInflater.from(context);
}
#Override
public RootViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = inflater.inflate(R.layout.root_row, viewGroup, false);
RootViewHolder rvi = new RootViewHolder(view);
return rvi;
}
#Override
public void onBindViewHolder(RootViewHolder rootViewHolder, int i) {
rootViewHolder.txtRootLine.setText(_items[i]);
rootViewHolder.recyclerViewChild.setLayoutManager(new LinearLayoutManager(inflater.getContext()));
rootViewHolder.recyclerViewChild.setAdapter(new ChildAdapter(inflater));
}
#Override
public int getItemCount() {
return _items.length;
}
class RootViewHolder extends RecyclerView.ViewHolder {
TextView txtRootLine;
RecyclerView recyclerViewChild;
public RootViewHolder(View itemView) {
super(itemView);
txtRootLine = (TextView) itemView.findViewById(R.id.txtRootLine);
recyclerViewChild = (RecyclerView) itemView.findViewById(R.id.recyclerChild);
}
}
}
private class ChildAdapter extends RecyclerView.Adapter<ChildAdapter.ChildViewHolder> {
private LayoutInflater _inflater;
String[] _childItems = new String[]{"child 1", "child 2", "child 2"};
public ChildAdapter(LayoutInflater inflater) {
_inflater = inflater;
}
#Override
public ChildViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = _inflater.inflate(R.layout.child_row, viewGroup, false);
ChildViewHolder rvi = new ChildViewHolder(view);
return rvi;
}
#Override
public void onBindViewHolder(ChildViewHolder childViewHolder, int i) {
childViewHolder.txtChildLine.setText(_childItems[i]);
}
#Override
public int getItemCount() {
return _childItems.length;
}
public class ChildViewHolder extends RecyclerView.ViewHolder {
TextView txtChildLine;
public ChildViewHolder(View itemView) {
super(itemView);
txtChildLine = (TextView) itemView.findViewById(R.id.txtChildLine);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="main text"/>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/recyclerRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
root_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/txtRootLine"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/recyclerChild"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
child_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/txtChildLine"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Existing layout manager does not support wrap content yet.
Test it by assigning a fixed height to your recyclerChild and the view would appear.
As a solution to this problem you can create a new LayoutManager that extends the existing one and overrides onMeasure method to measure for wrap content.
By Android Support Library 23.2 of a support library version 23.2.0. So all WRAP_CONTENT should work correctly.
Please update version of a library in gradle file.
compile 'com.android.support:recyclerview-v7:23.2.0'
RecyclerView does not support wrap_content.Set some value in nested recycler view like 200dp and your item will shows.
More discussion available here