RecyclerView inside nestedscrollview with bottom sheet behavior - android

I am making an app that displays post activities of different users like facebook. I have made postList Activity, in which username, his post image and post text will be displayed. Also want to implement like and comment feature in my app. On comment textview, bottomsheet will appear with list of comments of different users.
Problem is that i have used nestedscrollview with bottomsheet behavior. Inside nestedscroll view, there is recycler view.
here is my xml layout of bottomsheet
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/bottom_sheet1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/darker_gray"
android:fillViewport="true"
android:orientation="vertical"
app:behavior_hideable="true"
app:behavior_peekHeight="80dp"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<android.support.v7.widget.RecyclerView
android:id="#+id/commentList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.NestedScrollView>
This is Post List xml
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp">
<android.support.v7.widget.RecyclerView
android:id="#+id/post_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/addNewPost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true" />
</RelativeLayout>
</ScrollView>
<include layout="#layout/bottom_sheet" />
This is postlist adapter
public class CustomAdapter extends RecyclerView.Adapter<ViewHolder> {
NestedScrollView bottom_sheet;
CoordinatorLayout mainLayout;
private BottomSheetBehavior mBottomSheetBehavior;
public CustomAdapter(Context context, ArrayList<Post> posts,NestedScrollView
bottom_sheet,CoordinatorLayout mainLayout) {
this.posts = posts;
this.context = context;
this.bottom_sheet=bottom_sheet;
this.mainLayout=mainLayout;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_layout, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
mBottomSheetBehavior = BottomSheetBehavior.from(bottom_sheet);
mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_HIDDEN:
break;
case BottomSheetBehavior.STATE_EXPANDED: {
}
break;
case BottomSheetBehavior.STATE_COLLAPSED: {
}
break;
case BottomSheetBehavior.STATE_DRAGGING:
break;
case BottomSheetBehavior.STATE_SETTLING:
break;
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
}
});
holder.comment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mBottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
} else {
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
});
}
#Override
public int getItemCount() {
return posts.size();
}
}
And this is the adapter for comments
public class CommentAdapter extends RecyclerView.Adapter<CommentViewHolder> {
Context context;
public CommentAdapter(Context context,ArrayList<Comment> comments) {
this.comments = comments;
this.context=context;
}
#Override
public CommentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.comment_layout, parent, false);
CommentViewHolder viewHolder = new CommentViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(CommentViewHolder holder, int position) {
firebaseDatabase = FirebaseDatabase.getInstance();
commentReference = firebaseDatabase.getReference().child("Comments");
mAuth = FirebaseAuth.getInstance();
uId = mAuth.getCurrentUser().getUid();
final Comment comment = comments.get(position);
holder.commentUName.setText("Numrah");
holder.commentText.setText("hello");
holder.addCommentBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "comment", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return comments.size();
}
}
PostList Activity
public class PostList extends AppCompatActivity {
RecyclerView recyclerView;
ArrayList<Post> posts;
CustomAdapter customAdapter;
FloatingActionButton addPost;
FirebaseDatabase firebaseDatabase;
DatabaseReference postReference;
DatabaseReference likeReference;
DatabaseReference commentReference;
NestedScrollView bottomSheet;
CoordinatorLayout mainLayout;
private BottomSheetBehavior mBottomSheetBehavior;
RecyclerView commentRecyclerView;
ArrayList<Comment> comments;
CommentAdapter commentAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_post_list);
bottomSheet = (NestedScrollView) findViewById(R.id.bottom_sheet1);
mainLayout = (CoordinatorLayout) findViewById(R.id.main_layout);
commentRecyclerView=bottomSheet.findViewById(R.id.commentList);
comments = new ArrayList<>();
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
//layoutManager.setAutoMeasureEnabled(true);
commentRecyclerView.setLayoutManager(layoutManager);
commentRecyclerView.setNestedScrollingEnabled(false);
commentAdapter = new CommentAdapter(this, comments);
commentRecyclerView.setAdapter(commentAdapter);
firebaseDatabase = FirebaseDatabase.getInstance();
postReference = firebaseDatabase.getReference("Post");
likeReference = firebaseDatabase.getReference("Likes");
commentReference = firebaseDatabase.getReference("Comments");
posts = new ArrayList<>();
addPost = (FloatingActionButton) findViewById(R.id.addNewPost);
recyclerView = (RecyclerView) findViewById(R.id.post_list);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
customAdapter = new CustomAdapter(this, posts, bottomSheet, mainLayout);
recyclerView.setAdapter(customAdapter);
addPost.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(PostList.this, AddPost.class));
}
});
postReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Post post = dataSnapshot.getValue(Post.class);
posts.add(post);
customAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Post post = dataSnapshot.getValue(Post.class);
int indexOfItem = posts.indexOf(post);
if (indexOfItem >= 0) {
posts.set(indexOfItem, post);
}
customAdapter.notifyDataSetChanged();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#Override
public void onBackPressed() {
mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
if (mBottomSheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
super.onBackPressed();
} else {
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
}

As your arraylist comments is empty ( comments.size() is 0 ) the getItemCount() of your CommentAdapter is returning 0 . Hence zero rows will be inflated and your recyclerView would be blank. So your test case wont be executed To execute your test case try this in your CommentAdapter :-
#Override
public int getItemCount() {
return 5; // returning static no of items
}

Related

Problem with Recycler view in android studio - Only appearing occasionally

I`ve followed a tutorial to create a recyclerview for my app
I doesnt work, in that it only occasionally shows anything in the view
There doesnt appear to be any rime or reason at all...
The layout that is recycled
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="80dp">
<TextView
android:id="#+id/text_value"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="Test"
android:textColor="#000000"
android:textSize="18sp" />
</LinearLayout>
The xml with the recyclerview in it
<?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">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/recycler_view_accounts"/>
</LinearLayout>
The RecyclerViewAdapter class
public class RecyclerViewAdapterAccounts extends RecyclerView.Adapter<RecyclerViewAdapterAccounts.ViewHolder> {
private ArrayList<String> mlist;
private Context mContext;
public RecyclerViewAdapterAccounts(ArrayList<String> list, Context context) {
mlist = list;
mContext = context;
}
#NonNull
#Override
public RecyclerViewAdapterAccounts.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerViewAdapterAccounts.ViewHolder holder, final int position) {
holder.accountName.setText(mlist.get(position));
holder.parent_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, mlist.get(position), Toast.LENGTH_LONG).show();
}
});
}
#Override
public int getItemCount() {
return mlist.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView accountName;
LinearLayout parent_layout;
public ViewHolder(#NonNull View itemView) {
super(itemView);
accountName = itemView.findViewById(R.id.text_value);
parent_layout = itemView.findViewById(R.id.parent_layout);
}
}
}
The relevant onCreate activity
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_accounts);
initAccounts();
RecyclerView recyclerView = findViewById(R.id.recycler_view_accounts);
RecyclerViewAdapterAccounts adapter = new RecyclerViewAdapterAccounts(accounts, this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter.notifyDataSetChanged();
}
Although not shown, I can test that initAccounts() is filling the array as it should
I can also see that onCreateViewHolder and onBindViewHolder is not being called
Any suggestions???
edit:
heres the initAccounts
private void initAccounts() {
DatabaseReference userRef =
FirebaseDatabase.getInstance().getReference().child("users");
userRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
Iterator<DataSnapshot> children = snapshot.getChildren().iterator();
while (children.hasNext()) {
DataSnapshot child = children.next();
String[] parts = child.getValue().toString().split(",");
String role = parts[0].replace('{', ' ');
String msg = child.getKey() + ": " + role;
accounts.add(msg);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
The problem here is you are adding object to accounts but not notifying the Adapter about the change . Make the following changes to your code .
For setting adapter inside onCreate() use Only .
private RecyclerViewAdapterAccounts adapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manage_accounts);
initAccounts();
RecyclerView recyclerView = findViewById(R.id.recycler_view_accounts);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new RecyclerViewAdapterAccounts(accounts, this);
recyclerView.setAdapter(adapter);
}
Now create a method in RecyclerViewAdapterAccounts to add elements in adapter ;
public void addAll(ArratList<String> list){
mlist.clear();// To clear list if thats the case
mlist.addAll(list);
notifyDataSetChanged();
}
Now you can add all elements in one go to adapter .
public void onDataChange(#NonNull DataSnapshot snapshot) {
ArrayList<String> dataList=new ArrayList<>();
Iterator<DataSnapshot> children = snapshot.getChildren().iterator();
while (children.hasNext()) {
DataSnapshot child = children.next();
String[] parts = child.getValue().toString().split(",");
String role = parts[0].replace('{', ' ');
String msg = child.getKey() + ": " + role;
dataList.add(msg);
}
adapter.addAll(dataList);
}

Padding between Firebase RecyclerView items

I have been trying to get some padding between the Firebase RecyclerView items.I tried using ItemDecoration, but it works only with the first item of the RecyclerView.
Would be a great help if you could point out my mistake.
This is what I get
What I am trying to get is a layout where there is a padding between each recyclerview item so that I could see the shadow of each item.
Here's my Java code where I use the Firebase RecyclerView to load items.
public class CommunityFragment extends Fragment {
private static final String KEY_RECYCLER_STATE = "";
private RecyclerView mConvList;
private DatabaseReference mConvDatabase;
private DatabaseReference mUsersDatabase;
private DatabaseReference mMessageDatabase;
private Bundle mBundleRecyclerViewState;
private Parcelable mListState;
private static final String TAG = "ChatsFragment";
public CommunityFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mMainView = inflater.inflate(R.layout.fragment_chats, container, false);
mConvList = (RecyclerView) mMainView.findViewById(R.id.conv_list);
FirebaseAuth mAuth = FirebaseAuth.getInstance();
String mCurrent_user_id = Objects.requireNonNull(mAuth.getCurrentUser()).getUid();
mConvDatabase = FirebaseDatabase.getInstance().getReference().child("Chat").child(mCurrent_user_id);
mConvDatabase.keepSynced(true);
mUsersDatabase = FirebaseDatabase.getInstance().getReference().child("Users");
mUsersDatabase.keepSynced(true);
mMessageDatabase = FirebaseDatabase.getInstance().getReference().child("messages").child(mCurrent_user_id);
mMessageDatabase.keepSynced(true);
mConvList = mMainView.findViewById(R.id.conv_list);
mConvList.setHasFixedSize(true);
mConvList.setLayoutManager(new LinearLayoutManager(getContext()));
// Inflate the layout for this fragment
return mMainView;
}
#Override
public void onStart() {
super.onStart();
Query conversationQuery = mConvDatabase.orderByChild("timestamp");
FirebaseRecyclerOptions<Conv> friendsFirebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<Conv>()
.setQuery(conversationQuery, Conv.class)
.build();
FirebaseRecyclerAdapter<Conv, ConvViewHolder> firebaseConvAdapter = new FirebaseRecyclerAdapter<Conv, ConvViewHolder>(friendsFirebaseRecyclerOptions) {
#Override
protected void onBindViewHolder(#NonNull final ConvViewHolder holder, int position, #NonNull final Conv model) {
final String list_user_id = getRef(position).getKey();
assert list_user_id != null;
Query lastMessageQuery = mMessageDatabase.child(list_user_id).limitToLast(1);
lastMessageQuery.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
String data = Objects.requireNonNull(dataSnapshot.child("message").getValue()).toString();
String seen_ = Objects.requireNonNull(dataSnapshot.child("seen").getValue()).toString();
holder.setMessage(data, Boolean.parseBoolean(seen_));
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
mUsersDatabase.child(list_user_id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
final String userName = dataSnapshot.child("Name").getValue().toString();
holder.setName(userName);
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent chatIntent = new Intent(getContext(), ChatActivity.class);
chatIntent.putExtra("user_id", list_user_id);
chatIntent.putExtra("user_name",userName);
startActivity(chatIntent);
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
#NonNull
#Override
public ConvViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.single_q_layout, viewGroup, false);
return new ConvViewHolder(view);
}
};
mConvList.addItemDecoration(new PaddingItemDecoration(200));
firebaseConvAdapter.startListening();
mConvList.setAdapter(firebaseConvAdapter);
}
public void onPause(){
super.onPause();
mBundleRecyclerViewState = new Bundle();
mListState = mConvList.getLayoutManager().onSaveInstanceState();
mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, mListState);
}
public void onResume(){
super.onResume();
if (mBundleRecyclerViewState != null) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mListState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE);
mConvList.getLayoutManager().onRestoreInstanceState(mListState);
}
}, 50);
}
mConvList.setLayoutManager(new LinearLayoutManager(getContext()));
}
public class ConvViewHolder extends RecyclerView.ViewHolder {
View mView;
public ConvViewHolder(#NonNull View itemView) {
super(itemView);
mView = itemView;
}
public void setName(String name){
TextView userNameView = (TextView) mView.findViewById(R.id.question_title);
userNameView.setText(name);
}
public void setMessage(String message, boolean isSeen) {
TextView userStatusView = (TextView) mView.findViewById(R.id.question_catergory);
//Log.i("textData", "State is " + isSeen);
if(!isSeen){
userStatusView.setText("New Message");
userStatusView.setTypeface(userStatusView.getTypeface(), Typeface.BOLD);
}else{
userStatusView.setText("No New Messages");
userStatusView.setTypeface(userStatusView.getTypeface(), Typeface.NORMAL);
}
}
}
}
This is my PaddingItemDecoration class.
public class PaddingItemDecoration extends RecyclerView.ItemDecoration {
private final int size;
public PaddingItemDecoration(int size) {
this.size = size;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
// Apply offset only to first item
if (parent.getChildAdapterPosition(view) == 0) {
outRect.top += size;
outRect.bottom += size;
}
}
And this is the XML file of my Adapter I use to load my RecyclerView items.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:id="#+id/relativeLayout3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/message_text_background"
android:elevation="4dp"
android:padding="10dp">
<TextView
android:id="#+id/question_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:padding="10dp"
android:text="Display Name"
android:textColor="#020202"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/question_catergory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="catergory"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/question_title" />
<TextView
android:id="#+id/counter_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="counter"
app:layout_constraintEnd_toStartOf="#+id/answers_given"
app:layout_constraintTop_toBottomOf="#+id/question_title" />
<TextView
android:id="#+id/answers_given"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="answers"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/question_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
Instead of using this PaddingItemDecoration, just add margin around your XML file of adapter.
As I can see you already added padding to the parent constraint layout (try margin), so just remove your decoration class and just try simply printing list to screen, you should be good to go.
Below image is an example of ListItem layout for adapter from my app, yours also should look like this one.
Try to add margin 10dp
If you aren't able to do so, try implementing the way shown in this article.

particular title(fetched from api) using searchview?

I want something like this:
so the thing is, what I exactly want is when user type particular topic name(if present in-app) in searchview it should able give suggestions and if found it should open that topic activity (just like Facebook, Instagram,...etc searches)..and those title are coming from API(which I have successfully displayed in other activities)..like this:
..what will the logic for it??? need help... Thanks
so I have just included searchview in XML like this-->
<SearchView
android:id="#+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:queryHint="Search Here"
android:iconifiedByDefault="false"
android:layout_alignParentTop="true"
android:background="#drawable/search_bar"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="20dp"
android:pointerIcon="crosshair"
android:theme="#style/Widget.AppCompat.SearchView"
android:focusedByDefault="true"
/>
Need help..thanks in advance....
here is my json:
[{"id":"11","title":"TextView"},{"id":"10","title":"Edit Text"},{"id":"9","title":"ImageView"},{"id":"8","title":"Button "},{"id":"7","title":"CheckBox"},{"id":"6","title":"RadioButton & RadioGroup"},{"id":"5","title":"DatePicker"},{"id":"4","title":"TimePicker"},{"id":"3","title":"Switch"},{"id":"1","title":"Simple & Custom Toast"}]
here is my activity: for
public class StartLearning extends AppCompatActivity {
private RecyclerView recyclerView;
private SLAdapter slAdapter;
ProgressDialog progressDialog;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.startlearning_layout);
progressDialog = new ProgressDialog(StartLearning.this);
progressDialog.setMessage("Loading....");
progressDialog.show();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
/*Create handle for the RetrofitInstance interface*/
SLApiSevice service = SLApiClient.getRetrofitInstance().create(SLApiSevice.class);
Call<List<SlModel>> call = service.getMySlmodel();
call.enqueue(new Callback<List<SlModel>>() {
#Override
public void onResponse(Call<List<SlModel>> call, Response<List<SlModel>> response) {
progressDialog.dismiss();
generateDataList(response.body());
Log.e("hello", String.valueOf(response.body()));
}
#Override
public void onFailure(Call<List<SlModel>> call, Throwable t) {
progressDialog.dismiss();
Toast.makeText(getApplicationContext(), "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
});
}
}
private void generateDataList(List<SlModel> employeeList) {
recyclerView = findViewById(R.id.SLrecycle);
LinearLayoutManager manager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(manager);
recyclerView.setHasFixedSize(true);
slAdapter = new SLAdapter(getApplicationContext(),employeeList);
recyclerView.setAdapter(slAdapter);
}
adapter:
public class SLAdapter extends RecyclerView.Adapter<SLAdapter.CustomViewHolder> {
List<StartLearning.SlModel> Slmdel;
Context context;
public SLAdapter(Context context,List<StartLearning.SlModel> employees) {
this.Slmdel = employees;
this.context=context;
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.startlearning_item, parent, false);
return new CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
// TipsModel employee = employees.get(position);
//// holder.employeeName.setText(employees.get(position).getTips());
holder.textView.setText(String.valueOf(position+1)+". ");
holder.employeeName.setText(Slmdel.get(position).getTitle());
}
#Override
public int getItemCount() {
return Slmdel.size();
//return (employees == null) ? 0 : employees.size();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView employeeName;
TextView textView;
public CustomViewHolder(View view) {
super(view);
employeeName = (TextView) view.findViewById(R.id.Sl2);
textView=view.findViewById(R.id.Sl1);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, NextSLactivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("title", Slmdel.get(getAdapterPosition()).getTitle());
intent.putExtra("idSLnext", Slmdel.get(getAdapterPosition()).getId());
//Log.e("ashwini",WAmdel.get(getAdapterPosition()).getId());
context.startActivity(intent);
}
});
}
}
onclick of item(example :textview)
activity:one of the items(example :textview)
public class JavaFragment extends Fragment {
private RecyclerView recyclerView;
private NextSLJavaAdapter adapter;
private NextSLModel DescriptList;
ProgressDialog progressDialog;
public JavaFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.nextsl_layout, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Toolbar toolbar = (Toolbar) getView().findViewById(R.id. toolbar );
// setSupportActionBar( toolbar );
//if (getSupportActionBar() != null) {
// getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// getSupportActionBar().setDisplayShowHomeEnabled(true);
//}
progressDialog = new ProgressDialog(getContext());
progressDialog.setMessage("Loading....");
progressDialog.show();
Intent intent = getActivity().getIntent();
String title = intent.getStringExtra("title");
//getSupportActionBar().setTitle(title);
String id = intent.getStringExtra("idSLnext");
Log.e("ashwini", String.valueOf(id));
/*Create handle for the RetrofitInstance interface*/
SLApiSevice service = SLApiClient.getRetrofitInstance().create(SLApiSevice.class);
Call<NextSLModel> call = service.getnextslmodel(id);
call.enqueue(new Callback<NextSLModel>() {
#Override
public void onResponse(Call<NextSLModel> call, Response<NextSLModel> response) {
progressDialog.dismiss();
DescriptList=response.body();
generateDataList(DescriptList);
}
#Override
public void onFailure(Call<NextSLModel> call, Throwable t) {
progressDialog.dismiss();
Toast.makeText(getContext(), "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
});
}
private void generateDataList(NextSLModel photoList) {
recyclerView = getView().findViewById(R.id.nextSLrecycle);
LinearLayoutManager manager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(manager);
recyclerView.setHasFixedSize(true);
adapter = new NextSLJavaAdapter(getContext(),photoList);
recyclerView.setAdapter(adapter);
}
}
adapter:
public class NextSLJavaAdapter extends RecyclerView.Adapter<NextSLJavaAdapter.CustomViewHolder> {
NextSLModel Slmdel;
Context context;
public NextSLJavaAdapter(Context context, NextSLModel employees) {
this.Slmdel = employees;
this.context = context;
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.nextsl_item, parent, false);
return new CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
// TipsModel employee = employees.get(position);
//// holder.employeeName.setText(employees.get(position).getTips());
///////// holder.textView.setText(String.valueOf(position + 1) + ". ");
holder.employeeName.setText(Slmdel.getJava());
Log.e("sl",Slmdel.getJava());
}
#Override
public int getItemCount() {
return 1;
//return (employees == null) ? 0 : employees.size();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView employeeName;
TextView textView;
public CustomViewHolder(View view) {
super(view);
employeeName = (TextView) view.findViewById(R.id.detailsStartLearning);
textView = view.findViewById(R.id.Sl1);}}}
look at this search activity:
public class Search extends AppCompatActivity {
SearchView searchView;
RecyclerView recyclerView;
SearchAdapter slAdapter;
List<StartLearning.SlModel> movieList;
ChipGroup chipGroup;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
searchView=findViewById(R.id.searchView);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
searchForResults(newText);
return false;
}
});
//new code
chipGroup = findViewById(R.id. chipGroup);
searchView.onActionViewExpanded();
searchView.setIconified(true);
}
public void searchForResults(String search){
//here make an api call to get the results, complete the code here
SLApiSevice service = SLApiClient.getRetrofitInstance().create(SLApiSevice.class);
retrofit2.Call<List<StartLearning.SlModel>> call = service.getMySlmodel();
call.enqueue(new Callback<List<StartLearning.SlModel>>() {
#Override
public void onResponse(retrofit2.Call<List<StartLearning.SlModel>> call, Response<List<StartLearning.SlModel>> response) {
List<StartLearning.SlModel> list = response.body();
generateDataList(list);
addChips(list);
Log.d("TAG","Response = "+movieList);
slAdapter.setMovieList(getApplicationContext(),movieList);
}
#Override
public void onFailure(retrofit2.Call<List<StartLearning.SlModel>> call, Throwable t) {
Log.d("TAG","Response = "+t.toString());
}
});
}
private void generateDataList(List<StartLearning.SlModel> employeeList) {
recyclerView = findViewById(R.id.recyclerview);
LinearLayoutManager manager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(manager);
recyclerView.setHasFixedSize(true);
slAdapter = new SearchAdapter(getApplicationContext(),employeeList);
recyclerView.setAdapter(slAdapter);
}
public void addChips(List<StartLearning.SlModel> searchItems){
for (StartLearning.SlModel item : searchItems) {
Chip mChip = (Chip) this.getLayoutInflater().inflate(R.layout.item_chips, null, false);
mChip.setText(item.getTitle());
int paddingDp = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 10,
getResources().getDisplayMetrics()
);
mChip.setPadding(paddingDp, 0, paddingDp, 0);
mChip.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Handle the click here
}
});
chipGroup.removeAllViews();
chipGroup.addView(mChip);
}
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
}
xml of search:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" >
</androidx.appcompat.widget.Toolbar>
<SearchView
android:id="#+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:queryHint="Search Here"
android:iconifiedByDefault="false"
android:layout_alignParentTop="true"
android:background="#drawable/search_bar"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="20dp"
android:pointerIcon="crosshair"
android:theme="#style/Widget.AppCompat.SearchView"
android:focusedByDefault="true"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
<com.google.android.material.chip.ChipGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:id="#+id/chipGroup"
app:chipSpacing="25dp"/>
</LinearLayout>
Search adapter :
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.CustomViewHolder> implements Filterable {
List<StartLearning.SlModel> Slmdel;
List<StartLearning.SlModel> Slmdel1;
Context context;
public SearchAdapter() {
}
public void setMovieList(Context context, final List<StartLearning.SlModel> movieList){
this.context = context;
if(this.Slmdel == null){
this.Slmdel = movieList;
this.Slmdel1 = movieList;
notifyItemChanged(0, Slmdel1.size());
} else {
final DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {
#Override
public int getOldListSize() {
return SearchAdapter.this.Slmdel.size();
}
#Override
public int getNewListSize() {
// return movieList.size();
return (movieList == null) ? 0 : movieList.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return SearchAdapter.this.Slmdel.get(oldItemPosition).getTitle() == movieList.get(newItemPosition).getTitle();
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
StartLearning.SlModel newMovie = SearchAdapter.this.Slmdel.get(oldItemPosition);
StartLearning.SlModel oldMovie = movieList.get(newItemPosition);
return newMovie.getTitle() == oldMovie.getTitle() ;
}
});
this.Slmdel = movieList;
this.Slmdel1 = movieList;
result.dispatchUpdatesTo(this);
}
}
public SearchAdapter(Context context,List<StartLearning.SlModel> employees) {
this.Slmdel = employees;
this.context=context;
}
#Override
public SearchAdapter.CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.startlearning_item, parent, false);
return new SearchAdapter.CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(SearchAdapter.CustomViewHolder holder, int position) {
holder.employeeName.setText(Slmdel.get(position).getTitle());
}
#Override
public int getItemCount() {
if(Slmdel != null){
return Slmdel1.size();
} else {
return 0;
}
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
final FilterResults oReturn = new FilterResults();
final List<StartLearning.SlModel> results = new ArrayList<StartLearning.SlModel>();
if (Slmdel1 == null)
Slmdel1 = Slmdel;
if (constraint != null) {
if (Slmdel1 != null & Slmdel1.size() > 0) {
for (final StartLearning.SlModel g : Slmdel1) {
if (g.getTitle().toLowerCase().contains(constraint.toString()))
results.add(g);
}
}
oReturn.values = results;
}
return oReturn;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
Slmdel1 = (ArrayList<StartLearning.SlModel>) results.values;
notifyDataSetChanged();
}
};}
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView employeeName;
TextView textView;
public CustomViewHolder(View view) {
super(view);
employeeName = (TextView) view.findViewById(R.id.Sl2);
textView = view.findViewById(R.id.Sl1);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, NextSLactivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("title", Slmdel.get(getAdapterPosition()).getTitle());
intent.putExtra("idSLnext", Slmdel.get(getAdapterPosition()).getId());
//Log.e("ashwini",WAmdel.get(getAdapterPosition()).getId());
context.startActivity(intent);
}
});
}
}
}
You can achieve suggestions related to your search query using recyclerview and adapters.
[1] Create new adapter and put your setMovieList() and getFilter() into it.
[2] Set that adapter into recyclerview of suggestions and notify adapter when you get your arraylist of suggestions.
check below code
public void onResponse(retrofit2.Call<List<StartLearning.SlModel>> call, Response<List<StartLearning.SlModel>> response) {
movieList = response.body();
if(movieList.size()!=0){
tvSuggestions.setVisibility(View.VISIBLE);
suggestionAdapter=new SuggestionAdapter(Search.this,movieList);
recyclerViewSuggestions.setAdapter(suggestionAdapter);
Log.e("TAG", "onResponse: size of movielist "+movieList);
suggestionAdapter.getFilter().filter(query);
suggestionAdapter.notifyDataSetChanged();
suggestionAdapter.setMovieList(Search.this,movieList);
}
else{
tvSuggestions.setVisibility(View.VISIBLE);
tvSuggestions.setText("No Suggestions Found");
}
/*generateDataList(movieList);
Log.d("TAG","Response = "+movieList);
slAdapter.setMovieList(getApplicationContext(),movieList);*/
}
There is a new Chip Material Component in android. Which can be used to fullfill the requirements. I belive you are currently using some recyclerview to display those search items instead of using this use ChiGroup to hold those values.a
Below is some sample code to do
First add this to your gradle for using the external libarary dependency
implementation 'com.google.android.material:material:1.0.0-alpha1'
Then in your desired layout below the search view place this xml code.
<com.google.android.material.chip.ChipGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:id="#+id/chipGroup"
app:chipSpacing="25dp"/>
The ChipGroup will hold the Chip items which will be added dynamically.
So now in your search activity/fragment just get a reference of this layout group.
public class Search extends AppCompatActivity {
SearchView searchView;
ChipGroup chipGroup;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
searchView = findViewById(R.id.searchView);
//new code
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
searchForResults(newText);
return false;
}
});
//new code
chipGroup = findViewById(R.id. chipGroup);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
if (item.getItemId() ==android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
//new code
public void searchForResults(String search){
//here make an api call to get the results, complete the code here
call.enqueue(new Callback<List<StartLearning.SlModel>>() {
#Override
public void onResponse(retrofit2.Call<List<StartLearning.SlModel>> call, Response<List<StartLearning.SlModel>> response) {
List<StartLearning.SlModel> list = response.body();
//after getting the results pass to addChips()
addChips(list)
Log.d("TAG","Response = "+movieList);
}
#Override
public void onFailure(retrofit2.Call<List<StartLearning.SlModel>> call, Throwable t) {
Log.d("TAG","Response = "+t.toString());
}
});
}
//just call this when you get the search result from the api with your custom model and where ever it is applicable.
public void addChips(List<StartLearning.SlModel> searchItems){
for (StartLearning.SlModel item : searchItems) {
Chip mChip = (Chip) this.getLayoutInflater().inflate(R.layout.item_chip, null, false);
mChip.setText(item.title);
int paddingDp = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 10,
getResources().getDisplayMetrics()
);
mChip.setPadding(paddingDp, 0, paddingDp, 0);
mChip.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
// Handle the click here
}
});
chipGroup.removeAllViews();
chipGroup.addView(mChip);
}
}
}
I can't find the relevant code in Search activity to give an example. but the general idea is as below.
1) You add a ChipGroup to hold the Chip Views which will be added dynamically in your search view xml.
2) User Search something and you get the api response and you create a model based list.
3) you then iterate over the list one by one and create the dynamic chips.
4) But first create an item_chip.xml file with below content.
<com.google.android.material.chip.Chip xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:id=#+id/smallChip
style="#style/Widget.MaterialComponents.Chip.Choice"
android:textAppearance="?android:attr/textAppearance"
android:textColor="#color/secondaryTextColor"
app:chipBackgroundColor="#color/colorAccent" />
5) Now we are going to just inflate this layout file and add this to ChipGroup in for loop which we received earlier.
6) so the sample code goes like this to add the dynamic chips to ChipGroup. Here im using String as search items for simplicity you can use your own model here.
public void addChips(ArrayList<String> searchItems){
for (String item : searchItems) {
Chip mChip = (Chip) this.getLayoutInflater().inflate(R.layout.item_chip, null, false);
mChip.setText(item);
int paddingDp = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 10,
getResources().getDisplayMetrics()
);
mChip.setPadding(paddingDp, 0, paddingDp, 0);
mChip.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
// Handle the click here
}
});
chipGroup.addView(mChip);
}
}
now we have just added the chips dynamically to chipGroup which we declared earlier in search view layout . But this can also be done using Recyclerview instead of using ChipGropup just add the Chip View inside the recyclerview items and get a reference and set the text as you do with text views nothing to change except in adapter and item layout.
Edit: 4/1/20
Place the ChipGrop into the below XML file with search view. The idea is that the search view input box will be on top and the suggestions from the search will be just below the search box to give changing search results just right there on same screen. so call the search-related API call in the Search activity itself and pass the results to the sample method addChips() I have mentioned above.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<SearchView
android:id="#+id/searchView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:queryHint="Search Here"
android:iconifiedByDefault="false"
android:layout_alignParentTop="true"
android:background="#drawable/search_bar"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="20dp"
android:pointerIcon="crosshair"
android:theme="#style/Widget.AppCompat.SearchView"
android:focusedByDefault="true"/>
<com.google.android.material.chip.ChipGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:id="#+id/chipGroup"
app:chipSpacing="25dp"/>
</LinearLayout>
For more info read below blogs:
Material Design Chips
How to use Chips Blog
How to add Chips to ChipsGroup
Add this library in your gradle
implementation 'com.google.android.material:material:1.2.0-alpha02'
Change parent of AppTheme to Theme.MaterialComponents.Light.NoActionBar in values/styles.xml .just like this
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
Now You need to add edittext and chipgroup to your xml.Just like this
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/search_edittext"/>
<com.google.android.material.chip.ChipGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/chipgroup"
app:singleSelection="true"
>
</com.google.android.material.chip.ChipGroup>
Now create method add chip to chipgroup
void setChip(List<String> list)
{
chipgroup.removeAllViews();
for (String item : list)
{
Chip chip =new Chip(this);
chip.setText(item);
// necessary to get single selection working
chip.setCheckable(true);
chip.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("OnCheckedChangeListener", "Called");
}
});
//on chip click
chipgroup.addView(chip);
}
}
Now add addTextChangedListener to your edittext
search_edittext.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
List<String> tem=new ArrayList();
for (String item : list)
{
if (item.toString().toLowerCase().contains(s.toString().toLowerCase()))
tem.add(item);
}
setChip(tem);
}
});
And this done.
You can do this Chip View button you after spending little time i found this library will be more suitable in your case as you are trying to achieve with search view.
So Try this out :
Add this line to your module level build.gradle:
dependencies {
implementation "com.hootsuite.android:nachos:1.1.1"
}
Include a NachoTextView in your xml layout as follows:
<com.hootsuite.nachos.NachoTextView
android:id="#+id/nacho_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
You can look entire thing on github also as you want to achieve through search view look for this answer : SearchView query hint before clicking it

Creating chatapp using FirebaseRecyclerPagination

I'am trying to create a chat app using Firebase as database. I want to implement FirebaseRecyclerPagination because I don't want to load all the chat right away I want it to load by a certain number only per refresh. I'm following this tutorial [Sample App Using Firebase Recycler Pagination Library]
(https://firebaseopensource.com/projects/patilshreyas/firebaserecyclerpagination/app/readme.md). But still not getting the result I wanted.
Here is my current code
public class ChatTestActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private DatabaseReference mDatabase;
private SwipeRefreshLayout mSwipeRefreshLayout;
RecyclerView.LayoutManager layoutManager;
FirebaseRecyclerPagingAdapter<ChatMessage, PostViewHolder> mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_test);
mSwipeRefreshLayout = findViewById(R.id.swipe_refresh_layout);
//Initialize RecyclerView
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager mManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mManager);
//Initialize Database
mDatabase = FirebaseDatabase.getInstance().getReference().child("conversations").child("message");
final PagedList.Config config = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setInitialLoadSizeHint(2)
.setPrefetchDistance(2)
.setPageSize(2)
.build();
final DatabasePagingOptions<ChatMessage> options = new DatabasePagingOptions.Builder<ChatMessage>()
.setLifecycleOwner(this)
.setQuery(mDatabase, config, ChatMessage.class)
.build();
mAdapter = new FirebaseRecyclerPagingAdapter<ChatMessage, PostViewHolder>(options) {
#NonNull
#Override
public PostViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new PostViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_message, parent, false));
}
#Override
protected void onBindViewHolder(#NonNull PostViewHolder holder,
int position,
#NonNull ChatMessage model) {
holder.setItem(model);
}
#Override
protected void onLoadingStateChanged(#NonNull LoadingState state) {
switch (state) {
case LOADING_INITIAL:
case LOADING_MORE:
// Do your loading animation
mSwipeRefreshLayout.setRefreshing(true);
break;
case LOADED:
// Stop Animation
mSwipeRefreshLayout.setRefreshing(false);
break;
case FINISHED:
//Reached end of Data set
mSwipeRefreshLayout.setRefreshing(false);
break;
case ERROR:
retry();
break;
}
}
#Override
protected void onError(#NonNull DatabaseError databaseError) {
super.onError(databaseError);
mSwipeRefreshLayout.setRefreshing(false);
databaseError.toException().printStackTrace();
}
};
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
mAdapter.refresh();
}
});
mRecyclerView.setAdapter(mAdapter);
}
//Start Listening Adapter
#Override
protected void onStart() {
super.onStart();
mAdapter.startListening();
}
//Stop Listening Adapter
#Override
protected void onStop() {
super.onStop();
mAdapter.stopListening();
}
public class PostViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final TextView msgMessage;
public final TextView user;
TextView mAuthor;
TextView mDate;
public ChatMessage mItem;
public PostViewHolder(View view) {
super(view);
mView = view;
msgMessage = (TextView) view.findViewById(R.id.msgMessage);
user = (TextView) view.findViewById(R.id.user);
}
public void setItem(ChatMessage chatMessage){
msgMessage.setText(chatMessage.messageText);
user.setText(chatMessage.messageUser);
}
public TextView getMsgMessage() {
return msgMessage;
}
#Override
public String toString() {
return super.toString() + " '" + user.getText() + "'";
}
}
}
Here is my activity_chat_test.xml file
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout 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"
android:id="#+id/swipe_refresh_layout"
tools:context=".ChatTestActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/recycler_view">
</androidx.recyclerview.widget.RecyclerView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

Implementing Heterogeneous RecyclerView using firebase

I am trying to implement multiple view or so called heterogeneous recyclerview using firebase realtime database. I found a example of heterogeneous recyclerview implementation on github.
I followed this to implement on firebase. But my code didn't work.
fragment_search.java (one of the fragment in my tabbed view) This is my fragment file which contains the main recyclerview which will hold multiple views
public class fragment_search extends Fragment {
RecyclerView recyclerViewSearch;
private static SingleSearchBannerModel singleSearchBannerModel;
private static SingleSearchType1Model singleSearchType1Model;
private static DatabaseReference databaseReference;
private List<Object> objects = new ArrayList<>();
private static SearchMainAdapter searchMainAdapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_search,null);
//Recycler view initialized and Properties Set.
recyclerViewSearch = view.findViewById(R.id.recyclerview_search);
recyclerViewSearch.setHasFixedSize(true);
recyclerViewSearch.setLayoutManager(new LinearLayoutManager(getContext()));
databaseReference = FirebaseDatabase.getInstance().getReference();
return view;
}
private List<Object> getObjects(){
objects.addAll(getBannerData());
objects.addAll(getType1Data());
return objects;
}
public static List<SingleSearchBannerModel> getBannerData(){
final List<SingleSearchBannerModel> singleSearchBannerModelList = new ArrayList<>();
databaseReference.child("Featured").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
singleSearchBannerModel = dataSnapshot.getValue(SingleSearchBannerModel.class);
singleSearchBannerModelList.add(singleSearchBannerModel);
searchMainAdapter.notifyDataSetChanged();
System.out.println("this is image in getBanner == "+singleSearchBannerModel.getImage());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return singleSearchBannerModelList;
}
public static List<SingleSearchType1Model> getType1Data(){
final List<SingleSearchType1Model> singleSearchType1ModelList = new ArrayList<>();
databaseReference.child("Featured").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
singleSearchType1Model = dataSnapshot.getValue(SingleSearchType1Model.class);
singleSearchType1ModelList.add(singleSearchType1Model);
searchMainAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return singleSearchType1ModelList;
}
#Override
public void onStart() {
super.onStart();
searchMainAdapter = new SearchMainAdapter(getContext(),getObjects());
System.out.println("this is getObject == "+getObjects());
System.out.println("this is getBanner == "+getBannerData());
System.out.println("this is getType1 == "+getType1Data());
recyclerViewSearch.setAdapter(searchMainAdapter);
}
}
fragment_home.xml this is the xml file of fragment which contains one recyclerview (My main recyclerview).
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_search"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
Model files
*I have two model files. Basically getter and setters *
SingleSearchBannerModel.java My firsts model file.
public class SingleSearchBannerModel {
String Image;
public SingleSearchBannerModel() {
}
public SingleSearchBannerModel(String image) {
Image = image;
}
public String getImage() {
return Image;
}
public void setImage(String image) {
Image = image;
}
}
SingleSearchType1Model.java This is my second model file.
public class SingleSearchType1Model {
String Image;
public SingleSearchType1Model() {
}
public SingleSearchType1Model(String image) {
Image = image;
}
public String getImage() {
return Image;
}
public void setImage(String image) {
Image = image;
}
}
RecyclerView Adapters
Adapters are the ones used to set the value to the recyclerView. I have three Adapters as I'm trying to insert two views in one recyclerview. One is the MainAdapter which combines the other two Adapters. The MainAdapter is set to the the recyclerview of fragment_search.java (my main fragment)
SearchBannerAdapter.java This adapter is to generate the required layout file and populate the inflated layout file.
public class SearchBannerAdapter extends RecyclerView.Adapter<SearchBannerAdapter.TaskViewHolder>{
List<SingleSearchBannerModel> data;
public SearchBannerAdapter(List<SingleSearchBannerModel> data) {
this.data = data;
}
#NonNull
#Override
public TaskViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.search_single_banners,parent,false);
return new TaskViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull TaskViewHolder holder, int position) {
SingleSearchBannerModel singleSearchBannerModel = data.get(position);
Picasso.get().load(singleSearchBannerModel.getImage()).fit().into(holder.imageView);
}
#Override
public int getItemCount() {
return data.size();
}
public static class TaskViewHolder extends RecyclerView.ViewHolder{
View mView;
ImageView imageView;
public TaskViewHolder(View itemView) {
super(itemView);
mView = itemView;
imageView = mView.findViewById(R.id.search_banner_imgView);
}
}
}
search_single_banners.xml The xml file which is inflated in SearchBannerAdapter.java
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.CardView
android:layout_width="290dp"
android:layout_height="160dp"
android:id="#+id/longCard"
android:layout_marginTop="50dp"
android:layout_marginEnd="20dp"
app:cardCornerRadius="20sp"
app:cardElevation="#dimen/ten"
app:cardPreventCornerOverlap="false"
android:layout_centerHorizontal="true">
<ImageView
android:id="#+id/search_banner_imgView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/test1"/>
</android.support.v7.widget.CardView>
SearchType1Adapter.java This is the second adapter which inflates search_type_1.xml
public class SearchType1Adapter extends RecyclerView.Adapter<SearchType1Adapter.TaskViewHolder>{
List<SingleSearchType1Model> data;
public SearchType1Adapter(List<SingleSearchType1Model> data) {
this.data = data;
}
#NonNull
#Override
public TaskViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.search_type_1,parent,false);
return new TaskViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull TaskViewHolder holder, int position) {
SingleSearchType1Model singleSearchType1Model = data.get(position);
Picasso.get().load(singleSearchType1Model.getImage()).fit().into(holder.imageView);
}
#Override
public int getItemCount() {
return data.size();
}
public static class TaskViewHolder extends RecyclerView.ViewHolder{
View mView;
ImageView imageView;
public TaskViewHolder(View itemView) {
super(itemView);
mView = itemView;
imageView = mView.findViewById(R.id.search_single_type_1_imgView);
}
}
}
search_type_1.xml The file that is inflated in SearchType1Adapter.java
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.CardView
android:layout_width="290dp"
android:layout_height="160dp"
android:id="#+id/longCard"
android:layout_marginTop="50dp"
android:layout_marginEnd="20dp"
app:cardCornerRadius="20sp"
app:cardElevation="#dimen/ten"
app:cardPreventCornerOverlap="false"
android:layout_centerHorizontal="true">
<ImageView
android:id="#+id/search_single_type_1_imgView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/test1"/>
</android.support.v7.widget.CardView>
SearchMainAdapter.java This is the main adapter which is used in fragment_search to populate the main recyclerview.
public class SearchMainAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<Object> items;
private final int BANNER = 1;
private final int TYPE1 = 2;
public SearchMainAdapter(Context context, List<Object> items) {
this.context = context;
this.items = items;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view;
RecyclerView.ViewHolder holder;
switch (viewType){
case BANNER:
view = inflater.inflate(R.layout.search_banners,parent,false);
holder = new BannerViewHolder(view);
break;
case TYPE1:
view = inflater.inflate(R.layout.search_type_1,parent,false);
holder = new Type1ViewHolder(view);
break;
default:
view = inflater.inflate(R.layout.search_banners,parent,false);
holder = new Type1ViewHolder(view);
break;
}
return holder;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if(holder.getItemViewType() == BANNER)
BannerView((BannerViewHolder) holder);
else if (holder.getItemViewType() == TYPE1)
Type1View((Type1ViewHolder) holder);
}
private void BannerView(BannerViewHolder holder){
SearchBannerAdapter searchBannerAdapter = new SearchBannerAdapter(getBannerData());
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false));
holder.recyclerView.setAdapter(searchBannerAdapter);
}
private void Type1View(Type1ViewHolder holder){
SearchType1Adapter searchType1Adapter = new SearchType1Adapter(getType1Data());
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context,LinearLayoutManager.HORIZONTAL,false));
holder.recyclerView.setAdapter(searchType1Adapter);
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof SingleSearchBannerModel)
return BANNER;
if (items.get(position) instanceof SingleSearchType1Model)
return TYPE1;
return -1;
}
public static class BannerViewHolder extends RecyclerView.ViewHolder{
RecyclerView recyclerView;
public BannerViewHolder(View itemView) {
super(itemView);
recyclerView = itemView.findViewById(R.id.recyclerview_banners);
}
}
public static class Type1ViewHolder extends RecyclerView.ViewHolder{
RecyclerView recyclerView;
public Type1ViewHolder(View itemView) {
super(itemView);
recyclerView = itemView.findViewById(R.id.recyclerview_search_type_1);
}
}
}
search_banners.xml and search_type_1.xml have the same code
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_banners"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
The above code is not working. I want to know where i went wrong. My main objective is to make an app something like google play store or hotstar (In terms of UI). So I assume they are using single recyclerview and multiple view within it.
Thanks for help.
I know this answer is a bit late but it might still help someone in future. Here is how I achived the goal
public class HeteroActivity extends AppCompatActivity {
private ArrayList<Object> objects = new ArrayList<>();
private static final String TAG = HeteroActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hetero);
RecyclerView recyclerView = findViewById(R.id.recycler_View);
MainAdapter adapter = new MainAdapter(this, getObject());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
private ArrayList<Object> getObject() {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Data");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
objects.add(getVerticalData(dataSnapshot).get(0));
objects.add(getHorizontalData(dataSnapshot).get(0));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
return objects;
}
public static ArrayList<SingleVertical> getVerticalData(DataSnapshot dataSnapshot) {
ArrayList<SingleVertical> singleVerticals = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
singleVerticals.add(new SingleVertical(
snapshot.child("price").getValue(String.class),
snapshot.child("location").getValue(String.class),
snapshot.child("image").getValue(String.class)
));
Log.e(TAG,"Text loaded");
}
return singleVerticals;
}
public static ArrayList<SingleHorizontal> getHorizontalData(DataSnapshot dataSnapshot) {
ArrayList<SingleHorizontal> singleHorizontals = new ArrayList<>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
singleHorizontals.add(new SingleHorizontal(
snapshot.child("price").getValue(String.class),
snapshot.child("location").getValue(String.class),
snapshot.child("image").getValue(String.class)
));
Log.e(TAG,"Horizontal data loaded");
}
return singleHorizontals;
}
}
Then in your main Adapter
do this:
private void verticalView(final VerticalViewHolder holder) {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("Data");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
VerticalAdapter adapter1 = new VerticalAdapter(getVerticalData(dataSnapshot), context);
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context));
holder.recyclerView.setAdapter(adapter1);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
private void horizontalView(final HorizontalViewHolder holder) {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("Data");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
HorizontalAdapter adapter = new HorizontalAdapter(getHorizontalData(dataSnapshot),context);
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
holder.recyclerView.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}

Categories

Resources