Search code examples
androidandroid-fragmentsnavigationsearchview

SearchView implementation inside a particular Fragment


I have used navigation component in my project.It has a navigation drawer, only one Activity and a few fragment.The problem is, I want to implement SearchView to a particular Fragment which will be visible in that particular fragment only.... .. How can i achieve this?

My Fragment code:

public class HomeFragment extends Fragment {
FragmentHomeBinding homeBinding;
SharedPreferences preferences;
private DatabaseReference databaseReference;
List<Book> bookList;
RecyclerView.LayoutManager layoutManager;
BookAdapterHome adapter;
String user_key;
NavController navController;


public HomeFragment() {
    // Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    homeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false);
    return homeBinding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    navController = Navigation.findNavController(view);
    layoutManager = new LinearLayoutManager(getActivity());
    bookList = new ArrayList<>();
    adapter = new BookAdapterHome(bookList);
    homeBinding.allBooksRV.setLayoutManager(layoutManager);
    homeBinding.allBooksRV.setAdapter(adapter);
    databaseReference = FirebaseDatabase.getInstance().getReference("Books");

    preferences = this.getActivity().getSharedPreferences("MyPref", Context.MODE_PRIVATE);
    Boolean hasData = preferences.contains("user_key");
    if (hasData) {
        user_key = preferences.getString("user_key", "");

        PreparingAllData();
        settingUpListView();

    }


}

private void PreparingAllData() {
    databaseReference.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            bookList.clear();
            for (DataSnapshot singleBook : dataSnapshot.getChildren()) {
                Book book = singleBook.getValue(Book.class);
                bookList.add(book);
            }
            adapter.notifyDataSetChanged();

        }


        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });


}

private void settingUpListView() {
    adapter.setOnBookClickListener(new BookClickListener() {
        @Override
        public void onBookClick(int position, View v) {
            String bookId = bookList.get(position).getBookId();
            HomeFragmentDirections.ActionHomeToBookDetailsFragment action = HomeFragmentDirections.actionHomeToBookDetailsFragment();
            action.setBookId(bookId);
            navController.navigate(action);


        }

        @Override
        public void onBookLongClick(int position, View v) {


        }
    });

}

@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {

}

}

My Adapter Code:

public class BookAdapterHome extends RecyclerView.Adapter<BookAdapterHome.BookHolder>  implements Filterable {
List<Book> bookList;
List<Book> bookListFull;
private static BookClickListener bookClickListener;

public BookAdapterHome(List<Book> bookList) {

    this.bookList = bookList;
    bookListFull=new ArrayList<>(bookList);
}

@NonNull
@Override
public BookHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater layoutInflater =
            LayoutInflater.from(parent.getContext());
    SingleBookBinding bookBinding= DataBindingUtil.inflate(layoutInflater,R.layout.single_book,parent,false);
    return new BookHolder(bookBinding);
}

@Override
public void onBindViewHolder(@NonNull BookHolder holder, final int position) {
    final Book book=bookList.get(position);
    Picasso.get().load(book.getCoverLink()).placeholder(R.drawable.book_place_holder).into(holder.singleBookBinding.bookIV);
    holder.singleBookBinding.bookTitleTV.setText(book.getTitle());
    holder.singleBookBinding.bookEditionTV.setText("Edition: "+book.getEdition());
    holder.singleBookBinding.bookAuthorTV.setText("Author "+book.getAuthor());


}

@Override
public int getItemCount() {
    return bookList.size();
}

@Override
public Filter getFilter() {
    return bookFilter;
}

public class BookHolder extends RecyclerView.ViewHolder{
    private SingleBookBinding singleBookBinding;

    public BookHolder(@NonNull final SingleBookBinding bookBinding) {
        super(bookBinding.getRoot());
        this.singleBookBinding=bookBinding;
         bookBinding.getRoot().setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 bookClickListener.onBookClick(getAdapterPosition(),v);
             }
         });

    }
}

public void setOnBookClickListener(BookClickListener listener){
    bookClickListener =listener;
}
Filter bookFilter=new Filter() {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        List<Book> filteredBook=new ArrayList<>();
        if(constraint==null ||constraint.length()==0){
            filteredBook.addAll(bookListFull);
        }
        else{
            String filterPattern=constraint.toString().toLowerCase().trim();
            for(Book item:bookListFull){
              if(item.getBorrowerId().toLowerCase().contentEquals(filterPattern)){
                  filteredBook.add(item);
              }
            }
        }
        FilterResults results=new FilterResults();
        results.values=filteredBook;
        Log.e("constrain",constraint+" "+filteredBook.toString());
        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        bookList.clear();
        bookList.addAll((List)results.values);
        notifyDataSetChanged();

    }
};

}


Solution

  • To achieve fragment specific option menu besides activity's option menu you have to implement option menu in your fragment too.

    Activity:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }
    

    Fragment:

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true); // It's important here
    }
    
    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
        inflater.inflate(R.menu.fragment_menu, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }
    

    But there is a problem to order your menu item in the toolbar. You can specify the position of menu item in the toolbar using android:orderInCategory.

    activity_menu:

    <item
        android:id="@+id/action_menu1"
        android:title="Menu1"
        android:orderInCategory="2"
        app:showAsAction="always" />
    

    fragment_menu:

    <item
        android:id="@+id/action_search"
        android:title="Search"
        android:orderInCategory="1"
        app:showAsAction="always"
        app:actionViewClass="androidx.appcompat.widget.SearchView" />
    

    Output:
    enter image description here