Unable to get parent when bottomsheet called from fragment - java

I'm trying to set a peek height for my bottomsheet and I'm using this method below, it works fine when the BottomModalLayout is called from an activity but it doesnt when called from a fragment
Here is my code for bottomModalLayout
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
System.out.println("Details: "+view.getParent());
//CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) view.getParent()).getLayoutParams();
BottomSheetBehavior bottomSheetBehavior=BottomSheetBehavior.from((View) view.getParent());
//BottomSheetBehavior bottomSheetBehavior=params.getBehavior();
bottomSheetBehavior.setPeekHeight(1877);
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_DRAGGING) {
bottomSheetBehavior.setPeekHeight(1877);
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
}
});
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
this is called from a fragement
analysis.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
BottomModalLayout bottomSheet = new BottomModalLayout();
bottomSheet.setCancelable(false);
bottomSheet.show(getFragmentManager(),
"ModalBottomSheet");
}
});
but getting this error
Kindly Help!!!
and thanks in advance

When you want to deal with fragment you have to take into consideration the root.
By getting the root you can do any things in the fragment.
I think the error message is because you didn’t get the root.(the null because there’s no root found)
Try to use this in order to solve the problem:
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(getView().findViewById(R.id.parent_view_id));
The getView() method will help you to do so or you can use:
View rootView = getView();
// use the rootView in your code
I hope I explain the point correctly.
If you can show more of your code maybe I can help you more

Related

How can i access the find view by id of bottom nav outside on create in android

I am working on an application where I am using bottom navigation on Home where i have three fragments on the second fragment called Post Ad I have a button called enter fragment zone through that i enter into another fragment now when I enter inside another fragment now I don't want there to show the bottom navigation so to hide it I am using a method inside my main activity called "setBottomNavigationVisibility" where I am writing code to set the visibility of bottom nav. but the problem is that it is throwing the null pointer exception in the mainactivty's method saying that
"void com.google.android.material.bottomnavigation.BottomNavigationView.setVisibility(int)' on a null object reference" on the method's line where i am setting the visibility
code of MainActivity
public class MainActivity extends AppCompatActivity {
NavController navController;
BottomNavigationView bottomNavigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
navController = Navigation.findNavController(this, R.id.fragmentContainerView);
bottomNavigationView = findViewById(R.id.activity_main_bottom_navigation_view);
NavigationUI.setupWithNavController(bottomNavigationView, navController);
}
public void setBottomNavigationVisibility(int visibility) {
bottomNavigationView.setVisibility(visibility);
}}
On the above method when i am trying to setting the visibility on the line bottomNavigationView.setVisibility(visibility); that's where it is thrwoing the exception
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentSecondBinding.inflate(inflater, container, false);
// Inflate the layout for this fragment
View view = binding.getRoot();
viewModel = new ViewModelProvider(requireActivity()).get(PageViewModel.class);
((MainActivity) requireActivity()).setBottomNavigationVisibility(View.GONE);
binding.toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Navigation.findNavController(view).navigate(R.id.action_secondFragment2_to_postad);
}
});
No Please guide me how can i solve this error.
do something like this, define interface
interface DashboardActivityDelegate {
void hideBottomBar();
void showBottomBar();
}
your activity must implement this interface
and in your fragment in which you want to hide bottom nav view do this:
declare global variable
private DashboardActivityDelegate dashboardActivityDelegate;
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof DashboardActivityDelegate) {
dashboardActivityDelegate = (DashboardActivityDelegate)context;
}
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (dashboardActivityDelegate != null) {
dashboardActivityDelegate.hideBottomBar();
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (dashboardActivityDelegate != null) {
dashboardActivityDelegate.showBottomBar();
}
}
in fragment you want hide bottom bar, just call this line in onViewCreated
getActivity().findViewById(R.id.activity_main_bottom_navigation_view).setVisibility(View.GONE);
and when you leave fragment, call this line in onDestroy or onStop to visible bottom nav for another fragment:
getActivity().findViewById(R.id.activity_main_bottom_navigation_view).setVisibility(View.VISIBLE)

Android fragment navigation without button click

I am using a "Drawer Navigation" project using fragments and so far this method works:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Navigation.findNavController(view).navigate(R.id.nav_gallery);
}
});
But I want to use the navigation method inside a fragment class calling a function like this:
boolean b;
public void fragmentNavigation() {
if (b) {
Navigation.findNavController(getView()).navigate(R.id.nav_gallery);
}
}
I am a newbie using the navigation architecture and I still don't know if I need to declare some type of action listener for that function or how to make it work.
You can do that, but be careful of :
using getView() is Nullable; so you must make sure that your fragment has already created the view.
You can solve this by a couple of ways
First: Overriding onViewCreated() which has a nonNull view argument
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
fragmentNavigation(view);
}
boolean b;
public void fragmentNavigation(View view) {
if (b) {
Navigation.findNavController(view).navigate(R.id.nav_gallery);
}
}
Second: Create a View field in the fragment class, and set it within onCreateView()
View view;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.main_fragment, container, false);
return view;
}
then always call fragmentNavigation(view); on that view field.
Your fragment is hosted by the NavHostFragment of the Navigation Graph; so that you can avoid potential IllegalStateException

onResume() - for switching between multiple CHILD fragments

The basic problem I have is i'm trying to get a refresh function to execute every time i return to a specific fragment.
So far I've been using the workaround of utilizing setUserVisibleHint() as shown below.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
refresh();
}
}
However, this only works when switching between my main fragment and this fragment in question. What i'm wondering is how do i get this code to execute when i switch from one of my other tabs?
Help would be much appreciated.
Root cause: This is a feature from Android called offscreen page limit, it will retain the number of fragments to either side of current fragment, default value is 1. In your case using setUserVisibleHint is not enough to refresh data.
Solution:
public class YourFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,Bundle savedInstanceState) {
if (getUserVisibleHint()) { // fragment is visible to users.
refresh();
}
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && isResumed()) { // fragment is visible to users
refresh();
}
}
public void refresh(){
}
}
Fragments inside Pager act as visible even if there are not currently visible to user, the affected fragments are differ based on Pager offscreenPageLimit so trying to refresh fragment inside setUserVisibleHint or onResume has no effect when using Pager.
However that is fine as it is intended behavior, the aim of Pager is to let user switch between pages as you switch tabs in your browser..
If you still insist on refreshing pages you can do this inside the Pager addOnPageChangeListener like this:
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener(){
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + position);
if(fragment != null && fragment instanceof RefreshableFragment)
((RefreshableFragment) fragment).refresh();
}
});
Under the fragment, you should call your method under onResume() callback of fragment.
public void onResume(){
super.onResume();
.....
}

Access method from Dialog to MainActivity

I have a main Activity in which I created a ViewPager that instantiate 3 other Fragments. One of these is a GridView which makes a popup appear when the user click on one item. Then, in this popup, I have a simple button.
What I want to do is: when the user click on this button, I would like to access a method in my main Activity (that should change the current item of my ViewPager) and then dismiss the popup.
I tried everything I could, but I cannot achieve this... I can set up the click event on my popup and dismiss it easily, but I didn't find out how I can access a method (or even a variable) from my popup to my main Activity.
I will put my most relevant code in here so you can understand the structure of my classes (hopefully...).
My main Activity:
public class MainActivity extends FirstActivity{
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
// Set an Adapter on the ViewPager
mViewPager.setAdapter(new MainActivity_Adapter(getSupportFragmentManager()));
public void onSaveInstanceState(Bundle savedInstanceState)
{
menuBar.onSaveInstanceState(savedInstanceState);
}}
My ViewPager activity:
public class MainActivity_Adapter extends FragmentPagerAdapter{
public MainActivity_Adapter(FragmentManager fm)
{
super(fm);
}
#Override
public Fragment getItem(int position)
{
// Set the color background for each page
switch (position)
{
case 0:
return MainActivity_Inventory.newInstance();
case 1:
return MainActivity_Map.newInstance();
default:
return MainActivity_AR.newInstance();
}
}
// The number of Splash Screens to display
#Override
public int getCount()
{
return 3;
}}
My "Inventory" Fragment
public class MainActivity_Inventory extends Fragment implements View.OnClickListener{
public static MainActivity_Inventory newInstance()
{
MainActivity_Inventory frag = new MainActivity_Inventory();
Bundle b = new Bundle();
frag.setArguments(b);
return frag;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Select the layout
int layout;
layout = R.layout.activity_inventory_01;
// Inflate the layout resource file
View view = getActivity().getLayoutInflater().inflate(layout, container, false);
// Set the grid view
GridView gridview = (GridView) view.findViewById(R.id.inventory_gridView);
gridview.setAdapter(new InventoryImageAdapter(super.getActivity()));
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView parent, View v, int position, long id)
{
// Create a popup to show item details
createPopup();
}
});
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
}
public void createPopup()
{
DialogFragment newFragment = new PopupActivity_Inventory();
newFragment.show(getFragmentManager(), "itemDetails");
}
#Override
public void onClick(View v)
{
}}
And my popup dialog fragment:
public class PopupActivity_Inventory extends DialogFragment{
#Override
public Dialog onCreateDialog(final Bundle savedInstanceState)
{
// Build the alert dialog
final Dialog dialog = new Dialog(this.getActivity());
// Get the layout inflater
final LayoutInflater inflater = getActivity().getLayoutInflater();
// Set up the dialog box
dialog.setContentView(inflater.inflate(R.layout.activity_inventory_popup_01, null));
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.getWindow().setGravity(Gravity.TOP);
//dialog.getWindow().getAttributes().y = 100;
(dialog.findViewById(R.id.brick_button_01)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
// When button is clicked, ACCESS MAIN ACTIVITY!
dialog.dismiss();
}
});
return dialog;
}}
I really hope you can help me with this... I really need to get it working. Thank you very much!
If you need further details or explanation, please just tell me.
The best thing to do is use EventBus library. I have a demo app in which you can add items to RecyclerView from anywhere within the app using EventBus. You can use it as a reference to simply do something else instead of current task. Here is the link to the repo:
https://github.com/code-crusher/android-demos/tree/master/EventBusDemo
And if you want to understand how it works you can refer to my article, it explains how to make communications like this easy:
https://medium.com/#code_crusher/eventbus-for-android
Hope it helps. Happy coding :)
Read this https://developer.android.com/training/basics/fragments/communicating.html
Look for "To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity...."
Another way to achieve it is using an EventBus and post events by Fragments to be caught by Activities.

Android check what fragment sent onClick action

I have to build a simple app where I have 3 fragments, each contains 1 button.
If one of these buttons is pressed a site should load within a webview which is contained by the main activity. So far i have the basic callback to the activity working, but my question is. How do I check which button is pressed? Since they all seem to send the same view to the activity. I have tried to use the view.setTag() method but I couldn't get it to work.
Here is some of my code:
MainActivity.java
#Override
public void onClick(View v){
if(v.getId() == R.id.btnApple){
wvResult.loadUrl("http://www.apple.com");
}else if (v.getId() == R.id.btnMic){
wvResult.loadUrl("http://www.microsoft.com");
}else if(v.getId() == R.id.btnOracle){
wvResult.loadUrl("http://www.oracle.com");
}
}
One of the fragment classes (each is different in the names (apple, microsoft and oracle), the rest is exactly the same):
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.btn_a, container, false);
btnApple = (Button)v.findViewById(R.id.btnApple);
btnApple.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
callBack.onClick(v.getRootView());
}
});
return v;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
callBack = (View.OnClickListener) activity;
}
I hope someone can help me
Just pass v in your callback method (not v.getRootView()) because it is the view which was clicked.
View.getRootView() retrieves the root view element of view hieararchy, which is most likely one of the ViewGroup classes (LinearLayout, RelativeLayout, ...). That is the view which contains the clicked button.

Categories