In my RecyclerView I need replace part of my item to my fragment. But replacing only first item in recycler view. What I am doing is wrong?
My container (in recycler view item):
...
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/container" />
...
My update code in RecyclerView adapter:
...
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
...
}
...
I finnaly found solution. The problem is I set a common container id. But in recycler view need to set unique container id for each item.
So, my code now this:
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(UNIQUE_CONTAINER_ID, fragment).commit();
If someone will be useful, here is my complete code (implementation fragment in recycler view):
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
...
// Delete old fragment
int containerId = holder.mediaContainer.getId();// Get container id
Fragment oldFragment = fragmentManager.findFragmentById(containerId);
if(oldFragment != null) {
fragmentManager.beginTransaction().remove(oldFragment).commit();
}
int newContainerId = View.generateViewId();// Generate unique container id
holder.mediaContainer.setId(newContainerId);// Set container id
// Add new fragment
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(newContainerId, fragment).commit();
...
}
Upd.: Instead of using your own method to generate a unique id, it is recommended to use View.generateViewId()
Thanks to Mikhali, I'm able to provide to you a complete running example.
Pay special attention on the comments in onBindViewHolder()
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewLedgerAdapter.ViewHolder>{
private final String TAG = RecyclerViewAdapter.class.getSimpleName();
private final float FINAL_OPACITY = 0.3f;
private final float START_OPACITY = 1f;
private final int ANIMATION_TIME = 500;
private final int TYPE_ITEM = 0;
private final int TYPE_DATE = 1;
private final int TYPE_TRANSACTION = 2;
private final int TYPE_PENDING = 3;
private HashMap<Integer, Integer> mElementTypes;
private List<Operation> mObjects;
private Context mContext;
private Utils.CURRENCIES mCurrencySelected; // Which currency is already selected
private boolean mCurrencyFilter; // Defines if a currency is already selected to apply filter
private Animation mAnimationUp;
private Animation mAnimationDown;
public RecyclerViewLedgerAdapter(List<Operation> objects, Context context) {
mElementTypes = new HashMap<Integer, Integer>();
mObjects = objects;
mContext = context;
mCurrencyFilter = false;
mCurrencySelected = null;
mAnimationUp = AnimationUtils.loadAnimation(context, R.anim.slide_up);
mAnimationDown = AnimationUtils.loadAnimation(context, R.anim.slide_down);
}
...
...
Not needed methods
...
...
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_element_ledger, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
Operation operation = mObjects.get(position);
holder.setAppUserActivity(userActivityOperation);
// Remember that RecyclerView does not have onClickListener, you should implement it
holder.getView().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Hide details
// iDetailsContainer object could be checked on inner class ViewHolder
if(holder.iDetailsContainer.isShown()){
holder.iDetailsContainer.setVisibility(View.GONE);
}else{
// Show details
// Get fragment manager inside our fragment
FragmentManager fragmentManager = ((UserActivity)mContext).getSupportFragmentManager();
// Delete previous added fragment
int currentContainerId = holder.iDetailsContainer.getId();
// Get the current fragment
Fragment oldFragment = fragmentManager.findFragmentById(currentContainerId);
if(oldFragment != null) {
// Delete fragmet from ui, do not forget commit() otherwise no action
// is going to be observed
ragmentManager.beginTransaction().remove(oldFragment).commit();
}
// In order to be able of replacing a fragment on a recycler view
// the target container should always have a different id ALWAYS
int newContainerId = getUniqueId();
// Set the new Id to our know fragment container
holder.iDetailsContainer.setId(newContainerId);
// Just for Testing we are going to create a new fragment according
// if the view position is pair one fragment type is created, if not
// a different one is used
Fragment f;
if(position%2 == 0) {
f = new FragmentCard();
}else{
f=new FragmentChat();
}
// Then just replace the recycler view fragment as usually
manager.beginTransaction().replace(newContainerId, f).commit();
// Once all fragment replacement is done we can show the hidden container
holder.iDetailsContainer.setVisibility(View.VISIBLE);
}
}
// Method that could us an unique id
public int getUniqueId(){
return (int)SystemClock.currentThreadTimeMillis();
}
});
}
public class ViewHolder extends RecyclerView.ViewHolder{
private View iView;
private LinearLayout iContainer;
public LinearLayout iDetailsContainer;
private ImageView iOperationIcon;
private ImageView iOperationActionImage;
private TextView iOperation;
private TextView iAmount;
private TextView iTimestamp;
private TextView iStatus;
private UserActivityOperation mUserActivityOperation;
public ViewHolder(View itemView) {
super(itemView);
iView = itemView;
iContainer = (LinearLayout) iView.findViewById(R.id.operation_container);
iDetailsContainer = (LinearLayout) iView.findViewById(R.id.details_container);
iOperationIcon = (ImageView) iView.findViewById(R.id.ledgerOperationIcon);
iOperationActionImage = (ImageView) iView.findViewById(R.id.ledgerAction);
iOperation = (TextView) iView.findViewById(R.id.ledgerOperationDescription);
iAmount = (TextView) iView.findViewById(R.id.ledgerOperationCurrencyAmount);
iTimestamp = (TextView) iView.findViewById(R.id.ledgerOperationTimestamp);
iStatus = (TextView) iView.findViewById(R.id.ledgerOperationStatus);
// This linear layout status is GONE in order to avoid the view to use space
// even when it is not seen, when any element selected the Adapter will manage the
// behavior for showing the layout - container
iDetailsContainer.setVisibility(View.GONE);
}
...
...
Not needed methods
...
...
}
}
Layout
<?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:id="#+id/operation_container_maximum"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="11dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="11dp"
android:orientation="vertical">
<LinearLayout
android:id="#+id/operation_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="14dp">
<ImageView
android:id="#+id/ledgerOperationIcon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/fondear" />
<ImageView
android:id="#+id/ledgerAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:src="#drawable/operation_trade" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:weightSum="2">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="#+id/ledgerOperationDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Descripcion"
android:textColor="#color/ledger_desc" />
<TextView
android:id="#+id/ledgerOperationCurrencyAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="2dp"
android:text="5000 BTC" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<TextView
android:id="#+id/ledgerOperationTimestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Fecha/Hora"
android:textColor="#color/ledger_timestamp" />
<TextView
android:id="#+id/ledgerOperationStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Status" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/details_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Something hidden" />
<ImageView
android:layout_marginTop="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/user_btc"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
</LinearLayout>
Fragment
// This is one of the fragments used in the RecyclerViewAdapterCode, and also makes a HTTPRequest to fill the
// view dynamically, you could laso use any of your fragments.
public class FragmentCard extends Fragment {
TextView mTextView;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_card, container, false);
mTextView = (TextView) view.findViewById(R.id.tv_fragment_two);
new UserActivityAsyncTask().execute();
return view;
}
private UserActivityOperation[] asyncMethodGetPendingWithdrawals(){
BitsoWithdrawal[] userWithdrawals = HttpHandler.getUserWithdrawals(getActivity());
int totalWithDrawals = userWithdrawals.length;
UserActivityOperation[] appUserActivities = new UserActivityOperation[totalWithDrawals];
for(int i=0; i<totalWithDrawals; i++){
appUserActivities[i] = new UserActivityOperation(userWithdrawals[i], getActivity());
}
return appUserActivities;
}
private class UserActivityAsyncTask extends AsyncTask<String, Void, Integer> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Integer doInBackground(String... strings) {
// Precess Compound balance
UserActivityOperation[] compoundBalanceProcessed = asyncMethodGetPendingWithdrawals();
return compoundBalanceProcessed.length;
}
#Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
mTextView.setText(result.toString());
}
}
}
Related
I have the following classes:
CategoryFragment.java
public class CategoryFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "category_name";
// TODO: Rename and change types of parameters
private int mParam1;
public CategoryFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #return A new instance of fragment CategoryFragment.
*/
// TODO: Rename and change types and number of parameters
public static CategoryFragment newInstance(int param1) {
CategoryFragment fragment = new CategoryFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, param1);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getInt(ARG_PARAM1);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Context context = getActivity();
View view = inflater.inflate(R.layout.listado_noticias, container, false);
RecyclerView rw_noticias = view.findViewById(R.id.rw_noticias);
new LoadArticlesTask().execute(MainScreen.mPrefs,MainScreen.hasRemember,view,context,rw_noticias);
return null;
}
}
listado_noticias.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/constraintLayout"
xmlns:tools="http://schemas.android.com/tools">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rw_noticias"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
LoadArticlesTask.java
public class LoadArticlesTask extends AsyncTask<Object, Void, List<Article>> {
private static final String TAG = "LoadArticlesTask";
private View view;
private Context context;
private RecyclerView rw_noticias;
#Override
protected List<Article> doInBackground(Object... params) {
SharedPreferences sp = (SharedPreferences)params[0];
boolean hasRemember = (boolean)params[1];
view = (View)params[2];
context = (Context)params[3];
rw_noticias = (RecyclerView)params[4];
List<Article> res = null;
Properties ini = new Properties();
ini.setProperty(RESTConnection.ATTR_SERVICE_URL,Constants.URL_SERVICE);
ini.setProperty(RESTConnection.ATTR_REQUIRE_SELF_CERT,Constants.CERT_VALUE);
ModelManager.configureConnection(ini);
String strIdUser;
String strApiKey;
String strIdAuthUser;
if(hasRemember){
strIdUser = sp.getString("pref_apikey","");
strApiKey = sp.getString("pref_IdUser","");
strIdAuthUser = sp.getString("pref_strIdAuthUser","");
}else {
strIdUser = ModelManager.getLoggedIdUSer();
strApiKey = ModelManager.getLoggedApiKey();
strIdAuthUser = ModelManager.getLoggedAuthType();
}
//ModelManager uses singleton pattern, connecting once per app execution in enough
if (!ModelManager.isConnected()){
// if it is the first login
if (strIdUser==null || strIdUser.equals("")) {
try {
ModelManager.login(Constants.USER, Constants.PASS);
} catch (AuthenticationError e) {
Log.e(TAG, e.getMessage());
}
}
// if we have saved user credentials from previous connections
else{
ModelManager.stayloggedin(strIdUser,strApiKey,strIdAuthUser);
}
}
//If connection has been successful
if (ModelManager.isConnected()) {
try {
// obtain 6 articles from offset 0
res = ModelManager.getArticles(6, 0);
for (Article article : res) {
// We print articles in Log
Log.i(TAG, String.valueOf(article));
}
} catch (ServerCommunicationError e) {
Log.e(TAG,e.getMessage());
}
}
return res;
}
#Override
protected void onPostExecute(List<Article> articles) {
super.onPostExecute(articles);
Log.i("Articles", articles.toString());
for (Article article : articles) {
// We print articles in Log
Log.i("Articles", String.valueOf(article));
}
refreshList(articles,view);
}
public void refreshList(List<Article> data, View view){
if (data == null){
return;
}
for (Article article : data) {
// We print articles in Log
Log.i("Articles_rl", String.valueOf(article));
}
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rw_noticias.setLayoutManager(layoutManager);
ArticlesAdapter articlesAdapter = new ArticlesAdapter(data);
rw_noticias.setAdapter(articlesAdapter);
((ArticlesAdapter)rw_noticias.getAdapter()).updateData(data);
}
}
ArticlesAdapter.java
public class ArticlesAdapter extends RecyclerView.Adapter<ArticlesAdapter.ArticleViewHolder>{
private List<Article> articulos;
public ArticlesAdapter(List<Article> articulos){
this.articulos = articulos;
}
#NonNull
#Override
public ArticleViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_article, parent, false);
return new ArticleViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull ArticleViewHolder holder, int position) {
Bitmap imagen = null;
holder.category.setText(articulos.get(position).getCategory());
holder.title.setText(articulos.get(position).getTitleText());
holder.resumen.setText(articulos.get(position).getAbstractText());
try {
imagen = SerializationUtils.base64StringToImg(articulos.get(position).getImage().getImage());
} catch (ServerCommunicationError serverCommunicationError) {
serverCommunicationError.printStackTrace();
}
holder.thumbnail.setImageBitmap(imagen);
}
#Override
public int getItemCount() {
return articulos.size();
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public void updateData(List<Article>data){
articulos.clear();
articulos.addAll(data);
notifyDataSetChanged(); //notify to repaint the list
}
public void articlesFilterCategory(String category){
for (Article a : articulos){
if(!category.equals("ALL") && !a.getCategory().equals(category)){
articulos.remove(a);
}
}
}
public static class ArticleViewHolder extends RecyclerView.ViewHolder{
CardView cv;
TextView category;
TextView title;
TextView resumen;
ImageView thumbnail;
public ArticleViewHolder(#NonNull View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.card_article);
category = (TextView)itemView.findViewById(R.id.category_noticia);
resumen = (TextView)itemView.findViewById(R.id.resumen_noticia);
thumbnail = (ImageView)itemView.findViewById(R.id.thumbnail);
}
}
}
card_layout_article.xml
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?attr/selectableItemBackground"
android:ellipsize="end"
android:id="#+id/card_article"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp"
android:paddingHorizontal="1dp">
<ImageView
android:id="#+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="231dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="1dp"
android:layout_marginTop="1dp"
android:adjustViewBounds="true"
android:background="#drawable/a15877171854035"
android:cropToPadding="true"
android:scaleType="fitXY"
android:src="#drawable/degradado" />
<View
android:layout_width="match_parent"
android:layout_height="233dp"
android:background="#drawable/degradado" />
<TextView
android:id="#+id/title_noticia"
android:layout_width="193dp"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/thumbnail"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="107dp"
android:layout_marginEnd="107dp"
android:layout_marginBottom="95dp"
android:text="Nuevo caso de coronavirus"
android:textAlignment="center"
android:textColor="#color/cardview_light_background"
android:textSize="20dp"
android:textStyle="bold" />
<TextView
android:id="#+id/category_noticia"
android:layout_width="91dp"
android:layout_height="31dp"
android:layout_alignBottom="#+id/thumbnail"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="11dp"
android:layout_marginEnd="316dp"
android:layout_marginBottom="145dp"
android:text="NATIONAL"
android:textAlignment="center"
android:textColor="#color/cardview_light_background"
android:textSize="15dp"
android:textStyle="bold" />
<TextView
android:id="#+id/resumen_noticia"
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_alignBottom="#+id/thumbnail"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:layout_marginBottom="-1dp"
android:text="Nuevo caso de coronavirus"
android:textAlignment="viewStart"
android:textColor="#color/cardview_light_background"
android:textSize="11dp"
android:textStyle="bold" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
In the log.i that I have in the Post Execute of the async task I can see how the articles are formed (The Article class has a toString () function).
But I can't get the articles to be seen in the RecyclerView. What am I doing wrong?
Capture: Main screen with recyclerView empty...
Thanks!
Pass the instance of RecyclerView like -
new LoadArticlesTask().execute(MainScreen.mPrefs, MainScreen.hasRemember, view, rw_noticias, context);
Receive this on LoadArticlesTask as you are doing with View.
Don't re-initialize/use this code inside your class -
RecyclerView rw_noticias = view.findViewById(R.id.rw_noticias);
In your card_layout_article.xml, make height wrap_content for cardview:
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
........
........
Also in the layout of your recycler view instead of ConstraintLayout try to use RelativeLayout as the parent:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/constraintLayout"
xmlns:tools="http://schemas.android.com/tools">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rw_noticias"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
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 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.
When I launch a new fragment from my navigation drawer, it's meant to take me to a home page with a cardView of matching profiles. It works great the first time and every profile I want to show up is there. However, when I navigate away from the fragment and then click on it again, the elements are duplicated, and each subsequent time I refresh the page the items are duplicated once more. I believe this problem lies somewhere in my RecyclerView adapter not clearing on an activity create, but I have't been able to pinpoint it. Here's my fragment class
public class HomeFragment extends Fragment {
private CustomListAdapter listAdapter;
private static final String profileUrl = "http://10.0.2.2:3000/apip/buyers/profiles";
private static final String TAG = selectBuyerProfile.class.getSimpleName();
private ProgressDialog pDialog;
private ListView listView;
private List<BuyerProfile> buyersProfiles = new ArrayList<BuyerProfile>();
private View root;
//private RVAdapter recyclerAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_home, container, false);
return root;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
RecyclerView rv = (RecyclerView) getActivity().findViewById(R.id.rv);
//rv.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
rv.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(getActivity());
rv.setLayoutManager(llm);
rv.setItemAnimator(new DefaultItemAnimator());
final RVAdapter recyclerAdapter = new RVAdapter(buyersProfiles);
rv.setAdapter(recyclerAdapter);
RequestQueue mRequestQueue;
Cache cache = new DiskBasedCache(getActivity().getCacheDir(), 1024 * 1024);
Network network = new BasicNetwork(new HurlStack());
mRequestQueue = new RequestQueue(cache, network);
mRequestQueue.start();
JsonArrayRequest profileRequest = new JsonArrayRequest(profileUrl,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
// Parsing json
for(int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
BuyerProfile parsedProfile = new BuyerProfile();
parsedProfile.setBuyerProfTitle(obj.getString("title"));
parsedProfile.setDescription(obj.getString("description"));
parsedProfile.setLocations(obj.getString("locations"));
parsedProfile.setAssetTypes(obj.getString("asset_type"));
parsedProfile.setPropertyStatuses(obj.getString("property_status"));
//parsedProfile.setBuyerId("Select");
buyersProfiles.add(parsedProfile);
} catch (Exception e) {
e.printStackTrace();
}
}
recyclerAdapter.notifyDataSetChanged();
// notifying list adapter about data changes
// so that it renders the list view with updated data
//hidePDialog();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//Toast.makeText(selectBuyerProfile.this,"Error",Toast.LENGTH_LONG).show();
}
});
mRequestQueue.add(profileRequest);
}
}
And here is my RVAdapter class
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder> {
private Activity activity;
private LayoutInflater inflater;
private List<BuyerProfile> profileItems;
private static boolean itemFavorited;
RVAdapter(List<BuyerProfile> profiles) {
this.profileItems = profiles;
}
public static class PersonViewHolder extends RecyclerView.ViewHolder {
TextView name;
TextView description;
TextView locations;
TextView id;
TextView investmentRangeMin;
TextView investmentRangeMax;
TextView assetTypes;
TextView propertyStatuses;
ImageView favoriteButton;
CardView cardView;
PersonViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.titleText);
description = (TextView) itemView.findViewById(R.id.descriptionText);
investmentRangeMin = (TextView) itemView.findViewById(R.id.investmentRangeMin);
investmentRangeMax = (TextView) itemView.findViewById(R.id.investmentRangeMax);
locations = (TextView) itemView.findViewById(R.id.locations);
id = (TextView) itemView.findViewById(R.id.profileNumber);
assetTypes = (TextView) itemView.findViewById(R.id.assetTypes);
propertyStatuses = (TextView) itemView.findViewById(R.id.propertyStatuses);
favoriteButton = (ImageView) itemView.findViewById(R.id.favorite_select);
cardView = (CardView) itemView.findViewById(R.id.cv);
//User selects favorite on a matched profile
itemFavorited = false;
favoriteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!itemFavorited) {
favoriteButton.setImageResource(R.drawable.ic_favorite);
//cardView.setCardBackgroundColor(R.color.colorPrimary);
itemFavorited = true;
} else {
favoriteButton.setImageResource(R.drawable.ic_favorite_border);
itemFavorited = false;
}
}
});
}
}
#Override
public int getItemCount() {
return profileItems.size();
}
#Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
personViewHolder.name.setText(profileItems.get(i).getBuyerProfTitle());
personViewHolder.description.setText(profileItems.get(i).getDescription());
personViewHolder.locations.setText(profileItems.get(i).getLocations());
personViewHolder.assetTypes.setText(profileItems.get(i).getAssetTypes());
personViewHolder.propertyStatuses.setText(profileItems.get(i).getPropertyStatuses());
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
/*
#Override
public Object getItem(int location) {
return profileItems.get(location);
}
*/
#Override
public long getItemId(int position) {
return position;
}
}
Finally here is my fragments XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:padding="0dp"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Matches"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="false"
android:id="#+id/matchesText"
android:textAlignment="center"
android:textSize="20dp"
android:textColor="#color/navigationBarColor"
android:layout_alignParentStart="false"
android:layout_alignParentBottom="false"
android:layout_alignParentLeft="false"
android:layout_alignParentRight="true"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rv"
android:layout_below="#id/matchesText"
/>
<!-- Thumbnail Image -->
<ImageView
android:id="#+id/imgBillionaire"
android:src="#drawable/ic_perm_identity"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentLeft="true"
android:layout_marginRight="8dp"
android:layout_alignParentEnd="false"
android:layout_alignParentStart="true"
android:nestedScrollingEnabled="false"
android:visibility="invisible"/>
<!-- Name of Asset -->
<TextView
android:id="#+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/imgBillionaire"
android:layout_toRightOf="#+id/imgBillionaire"
android:textSize="#dimen/Title"
android:textStyle="bold" />
<!-- Description -->
<TextView
android:id="#+id/descriptionText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/titleText"
android:layout_marginTop="1dip"
android:layout_toRightOf="#+id/imgBillionaire"
android:textSize="#dimen/Description" />
<!-- Source -->
<TextView
android:id="#+id/locations"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/descriptionText"
android:layout_marginTop="5dp"
android:layout_toRightOf="#+id/imgBillionaire"
android:textColor="#color/wealthsource"
android:textSize="#dimen/InvestmentRange" />
<!-- Source -->
<TextView
android:id="#+id/assetTypes"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/locations"
android:layout_marginTop="5dp"
android:layout_toRightOf="#+id/imgBillionaire"
android:textColor="#color/wealthsource"
android:textSize="#dimen/InvestmentRange" />
<!-- Source -->
<TextView
android:id="#+id/propertyStatuses"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/assetTypes"
android:layout_marginTop="5dp"
android:layout_toRightOf="#+id/imgBillionaire"
android:textColor="#color/wealthsource"
android:textSize="#dimen/InvestmentRange" />
<!-- Year -->
<TextView
android:id="#+id/profileNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="false"
android:layout_alignParentRight="true"
android:textColor="#color/year"
android:textSize="#dimen/Date" />
</RelativeLayout>
</LinearLayout>
Any ideas why the items in my recyclerview would keep duplicating on each page refresh?
What can possibly be happening is that each time the network request returns, it tries to add every new item to an already existing list inside the fragment.
Depending on how you implement your navigation logic, your fragment won't be destroyed by the system once you navigate away from it, instead calling a series of lifecycle callbacks:
onPause() -> onStop() -> onDestroyView()
And when you return to the fragment, all required lifecycle callbacks will be called until it reaches the active state.
onCreateView() -> onActivityCreated() -> onStart() -> onResume()
More information on fragment's lifecycle works can be found here: https://developer.android.com/guide/components/fragments.html
Since your fragment is not getting destroyed and recreated, your buyersProfiles reference may hold the previous data when you return. Since the network call is not overwriting the original list, it will append the new data fetched from the network next to the existing data each time it calls it's onResponse callback.
This may also affect use cases where you implement some kind of pull-to-refresh logic or refresh button, as the new network call will not clean the list.
One thing you could try to avoid this repetition is adding
buyersProfiles = new ArrayList<BuyerProfile>();
to the top of your onResponse() callback.
Hope it helps.
I am using linkify to make links clickable in the textview. But whenever text length is big, the text flickers on scrolling or sometimes just disappears. The text view is part of header of recyclerview. Posting relevant code from activity class, its xml and adapter.
The Activity:
public class NewDiscussionDetailActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_discussion_detail);
Toolbar toolbar = (Toolbar) findViewById(R.id.detail_toolbar);
aQuery = new AQuery(this);
setSupportActionBar(toolbar);
final ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setDisplayHomeAsUpEnabled(true);
ab.setTitle("Discussion");
}
Intent activityIntent = getIntent();
discussion_id = Integer.parseInt(activityIntent.getStringExtra("discussion_id"));
discussion_title = activityIntent.getStringExtra("discussion_title");
discussion_text = activityIntent.getStringExtra("discussion_text");
discussion_image_url = activityIntent.getStringExtra("discussion_image_url");
comment_count = Integer.parseInt(activityIntent.getStringExtra("discussion_comment_no"));
community_id = activityIntent.getStringExtra("community_id");
community_name = activityIntent.getStringExtra("community_name");
is_from_notification = activityIntent.getBooleanExtra("is_notification", false);
// initializing header and footer for List view
footer = getLayoutInflater().inflate(R.layout.main_list_footer, null);
header = getLayoutInflater().inflate(R.layout.discussion_detail_header, null);
prepareHeader(header);
recyclerView = (RecyclerView) findViewById(R.id.comment_list);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(recyclerView.getContext());
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mLayoutManager.canScrollVertically();
recyclerView.setLayoutManager(mLayoutManager);
adapter = new CommentAdapter(commentList, this);
/* download page 1*/
adapter.addHeader(header);
recyclerView.setAdapter(adapter);
getCommentList();
/* Scroll Listener which takes care of all triggers to download to load data to adapter based position of the view*/
// code for downloading more pages of comments
}
private void prepareHeader(View header) {
/* preparing the header*/
discussion_image = (ImageView) header.findViewById(R.id.discussion_image_1);
title = (TextView) header.findViewById(R.id.discussion_title);
commentno = (TextView) header.findViewById(R.id.comment_count);
description = (TextView) header.findViewById(R.id.discussion_text_content);
title.setText(discussion_title);
title.setTypeface(AppConstants.getTypeFaceBold(this));
description.setText(discussion_text);
discriptionText = discussion_text + "";
Linkify.addLinks(description, Linkify.WEB_URLS);
description.setTypeface(AppConstants.getTypeFaceNormal(this));
if (comment_count > 2) {
commentno.setText(String.valueOf(comment_count - 1) + " comments");
} else if (comment_count == 2){
commentno.setText(String.valueOf(comment_count - 1) + " comment");
}else {
commentno.setText("Be the first to comment");
}
if (discussion_image_url == null || discussion_image_url.equals("")) {
discussion_image.setVisibility(View.GONE);
//progressbar.setVisibility(View.GONE);
} else {
discussion_image.setVisibility(View.VISIBLE);
final String image_url = discussion_image_url;
if(UtilMethod.isStringNullOrBlank(image_url))
{
//progressbar.setVisibility(View.GONE);
}
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width=dm.widthPixels;
int height=dm.heightPixels;
Picasso.with(this)
.load(image_url)
.placeholder(R.drawable.default_img_big).error(R.drawable.default_img_big)
.transform(new ImageTransformation(width))
.into(discussion_image, new Callback() {
#Override
public void onSuccess() {
// TODO Auto-generated method stub
//progressbar.setVisibility(View.GONE);
}
#Override
public void onError() {
// TODO Auto-generated method stub
//progressbar.setVisibility(View.GONE);
}
});
discussion_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// code
}
});
}
}
The Adapter:
public class CommentAdapter extends RecyclerView.Adapter<CommentAdapter.CustomViewHolder> {
ArrayList<CommentListBean> mArrayList;
Context mContext;
String event = "";
public static final int TYPE_HEADER = 111;
public static final int TYPE_FOOTER = 222;
public static final int TYPE_ITEM = 333;
//headers
List<View> headers = new ArrayList<>();
//footers
List<View> footers = new ArrayList<>();
// 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 static class CustomViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
private View view;
final TextView timestamp_tv;
final TextView chat_username;
final TextView description_tv;
final ImageView author_image_view;
final ImageView comment_image;
public CustomViewHolder(View v) {
super(v);
view = v;
chat_username = (TextView) v.findViewById(R.id.comment_author_chatname);
timestamp_tv = (TextView) v.findViewById(R.id.comment_timestamp);
description_tv = (TextView) v.findViewById(R.id.comment_text);
comment_image = (ImageView) v.findViewById(R.id.comment_image);
author_image_view = (ImageView) v.findViewById(R.id.comment_author_image);
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public CommentAdapter(ArrayList<CommentListBean> arrayList, Context context) {
this.mContext = context;
this.mArrayList = arrayList;
}
// Create new views (invoked by the layout manager)
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
if (viewType == TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.comment_list_item, null);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
} else {
//create a new framelayout, or inflate from a resource
FrameLayout frameLayout = new FrameLayout(parent.getContext());
//make sure it fills the space
frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
return new HeaderFooterViewHolder(frameLayout);
}
}
// Replace the contents of a view (invoked by the layout manager)
public void onBindViewHolder(final CustomViewHolder holder, final int position) {
//check what type of view our position is
if(position < headers.size()){
View v = headers.get(position);
//add our view to a header view and display it
prepareHeaderFooter((HeaderFooterViewHolder) holder, v);
}else if(position >= headers.size() + mArrayList.size()){
View v = footers.get(position-mArrayList.size()-headers.size());
//add oru view to a footer view and display it
prepareHeaderFooter((HeaderFooterViewHolder) holder, v);
}else {
// - code for normal comment view
}
}
#Override
public int getItemViewType(int position) {
//check what type our position is, based on the assumption that the order is headers > items > footers
if(position < headers.size()){
return TYPE_HEADER;
}else if(position >= headers.size() + mArrayList.size()){
return TYPE_FOOTER;
}
return TYPE_ITEM;
}
private void prepareHeaderFooter(HeaderFooterViewHolder vh, View view){
//empty out our FrameLayout and replace with our header/footer
vh.base.removeAllViews();
vh.base.addView(view);
}
//add a header to the adapter
public void addHeader(View header){
if(!headers.contains(header)){
headers.add(header);
//animate
notifyItemInserted(headers.size()-1);
}
}
//remove a header from the adapter
public void removeHeader(View header){
if(headers.contains(header)){
//animate
notifyItemRemoved(headers.indexOf(header));
headers.remove(header);
}
}
//add a footer to the adapter
public void addFooter(View footer){
if (!footers.contains(footer)){
footers.add(footer);
//animate
notifyItemInserted(headers.size()+mArrayList.size()+footers.size()-1);
}
}
//remove a footer from the adapter
public void removeFooter(View footer){
if(footers.contains(footer)) {
//animate
notifyItemRemoved(headers.size()+mArrayList.size()+footers.indexOf(footer));
footers.remove(footer);
}
}
//our header/footer RecyclerView.ViewHolder is just a FrameLayout
public static class HeaderFooterViewHolder extends CustomViewHolder{
FrameLayout base;
public HeaderFooterViewHolder(View itemView) {
super(itemView);
this.base = (FrameLayout) itemView;
}
}
}
XML for the header view
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/margin_10">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/message_list_image_layout"
android:orientation="horizontal"
android:paddingTop="20dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="Representative image for the discussion"
android:background="#color/background_color"
android:id="#+id/discussion_image_1"
android:layout_marginBottom="#dimen/margin_5"
android:layout_marginTop="#dimen/margin_5"
android:src="#drawable/bg"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:maxHeight="280dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/discussion_title"
android:text="This is heading of the content"
android:layout_marginLeft="#dimen/margin_20"
android:layout_marginRight="#dimen/margin_20"
style="#style/Base.TextAppearance.AppCompat.Display1"
android:alpha="075" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/discussion_text_content"
android:layout_marginTop="#dimen/margin_10"
android:layout_marginLeft="#dimen/margin_20"
android:layout_marginRight="#dimen/margin_20"
android:text="this is the text of content. this is the text of content. this is the text of content. this is the text of content. this is the text of content.this is the text of content. this is the text of content. this is the text of content. this is the text of content. this is the text of content."
style="#style/Base.TextAppearance.AppCompat.Body1"
android:alpha="0.75" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="#dimen/margin_10"
android:layout_marginLeft="#dimen/margin_20"
android:layout_marginRight="#dimen/margin_20"
android:background="#color/dark_background_color"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="#dimen/margin_10"
android:layout_marginBottom="#dimen/margin_10"
android:layout_marginRight="#dimen/margin_20"
android:layout_marginLeft="#dimen/margin_20"
android:gravity="center_vertical|right|end"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/comment_count"
android:text="4 comments" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
Screenshots
Normal view
when I scroll a bit
I have a feeling that it has something to do with LinkMovementMethod. Please help.