I have been using the NavigationDrawer activity. I have been calling the fragment from the activity. It gets called successfully but the actionbar is not showing up.
Code: Gallery_Frag - an activity created to extend teh fragment that i want to show up.
public class Gallery_Frag extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.app_bar_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (savedInstanceState == null){
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, new GalleryFragment()).commit(); }
}
CODE: GalleryFragment
public class GalleryFragment extends Fragment {
private GalleryViewModel galleryViewModel;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
galleryViewModel =
ViewModelProviders.of(this).get(GalleryViewModel.class);
View root = inflater.inflate(R.layout.fragment_gallery, container, false);
/* final TextView textView = root.findViewById(R.id.text_gallery);
galleryViewModel.getText().observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
textView.setText(s);
}
});*/
return root;
}}
CODE: manifest
<activity android:name=".Gallery_Frag"
android:label="My Bookings"
android:theme="#style/AppTheme.NoActionBar"/>
CODE:app_bar_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="#layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
CODE: content_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_main">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/mobile_navigation" />
</RelativeLayout>
You may have a container inside this content_main.xml;
if yes, pass that id to the add(R.id.container_id, new GalleryFragment())...
Otherwise change <include layout="#layout/content_main" /> to
<include layout="#layout/content_main"
android:id="#+id/fragment_container"/>
and use
add(R.id.fragment_container, new GalleryFragment())...
First of all, you have to set layout to Activity using setContentView which contain Toolbar
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set it first
setContentView(R.layout.your_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (savedInstanceState == null){
getSupportFragmentManager().beginTransaction()
.add(R.id.content, new GalleryFragment()).commit(); }
}
Got it
In your content_main.xml file, add an id to the parent relative layout like below,
<RelativeLayout
android:id="#+id/fragment_container"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_main">
And replace,
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, new GalleryFragment()).commit();
with
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new GalleryFragment()).commit();
This will hopefully work.
Related
I am building android shopping app that have the cart menu item and all products are opening in fragment and i want to set the MainActivity menu items on the product fragment and other fragments.
So the user is easy to open the cart from the product view fragment.below code
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.product_view_fragment, null);
setHasOptionsMenu(true);
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
getActivity().invalidateOptionsMenu();
toolbar = (Toolbar)view.findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getActivity().onBackPressed();
}
});
this.context = getContext();
String id=getArguments().getString("message");
//String size=getArguments().getString("size");
viewPager = (ViewPager)view.findViewById(R.id.viewPager);
SessionManager sessionManager = new SessionManager(getContext());
email = sessionManager.getUserDetails().get("id");
sliderDotspanel = (LinearLayout)view.findViewById(R.id.SliderDots);
GetOneProduct(id);
return view;
}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
xmlns:segmentedgroup="http://schemas.android.com/tools"
android:orientation="vertical"
android:clickable="true"
android:background="#color/colorWhite"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#android:style/Animation.Activity">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:navigationIcon="?attr/homeAsUpIndicator"
app:popupTheme="#style/AppTheme.PopupOverlay"
app:titleTextColor="#color/Black" />
</android.support.design.widget.AppBarLayout>
Blockquote
I assume you use a single activity approach.
Then your activity should include Toolbar in its layout something like this.
<android.support.constraint.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".navigation.HomeActivity">
<androidx.appcompat.widget.Toolbar></androidx.appcompat.widget.Toolbar>
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/app_navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView>
// if you have bottom nav.
</com.google.android.material.bottomnavigation.BottomNavigationView>
Then set up the toolbar as you wish in your activity.
I am having troubling sending data from one fragment to another fragment. I was following the android guideline which tells me to create an interface to communicate with activity and fragments. I'm using the bottom navigation to switch over fragments.
Anyway, here's the error from android studio:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.makkhay.cameratranslate.Favorite.displayReceivedData(java.lang.String)' on a null object reference
at com.example.makkhay.cameratranslate.HomeActivity.sendData(HomeActivity.java:143)
at com.example.makkhay.cameratranslate.HomeFragment$2.onClick(HomeFragment.java:162)
at android.view.View.performClick(View.java:6256)
at android.view.View$PerformClick.run(View.java:24697)
at android.os.Handler.handleCallback(Handler.java:789)
For some reason, my fragments are always null even after initializing it. I tried initializing it both ways, onCreate method, and the sendData method, the instance always seems to be null. I think the main culprit might be the DrawerLayout. Since it is the parent xml and there is another xml called "app_bar_home.xml"; which is hosting the two fragments using bottom navigation, the newly created instances are always null
Here's my main activity which is holding two fragments
HomeActivity.java
public class HomeActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener,HomeFragment.SendMessage {
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
selectedFragment = new HomeFragment();
break;
case R.id.navigation_favorite:
selectedFragment = new Favorite();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.app_bar,
selectedFragment).commit();
return true;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
//I added this if statement to keep the selected fragment when rotating the device
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.app_bar,
new HomeFragment()).commit();
}
}
#Override
public void sendData(String message) {
Favorite f = (Favorite) getSupportFragmentManager().findFragmentById(R.id.favFragment);
f.displayReceivedData(message);
}
}
Here's my xml for my activity
activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
android:id="#+id/app_bar"
layout="#layout/app_bar_home"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_home"
app:menu="#menu/activity_home_drawer" />
</android.support.v4.widget.DrawerLayout>
Here's the app_bar_home.xml which is also part of the activity
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
app:layout_collapseMode="pin"
android:id="#+id/toolbar"
/>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#000"
app:itemIconTint="#color/color_selector"
app:itemTextColor="#color/color_selector"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/navigation" />
</android.support.constraint.ConstraintLayout>
Here's the fragment 1 from which I want to send the data to another fragment.
HomeFragment.java
public class HomeFragment extends Fragment implements View.OnClickListener{
SendMessage SM;
private Button clearButton, favButton, shareButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_home, container, false);
return v;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
favButton = view.findViewById(R.id.favButton);
favButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SM.sendData(" test");
}
});
}
interface SendMessage {
void sendData(String message);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
SM = (SendMessage) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException("Error in retrieving data. Please try again");
}
}
}
HomeFragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/homeFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeFragment"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
app:layout_collapseMode="pin" />
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="6dp"
android:layout_marginEnd="6dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginStart="6dp"
android:layout_marginTop="56dp"
android:background="#drawable/card_shadow"
android:divider="?android:dividerHorizontal"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:showDividers="middle">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingBottom="16dp"
android:gravity="right"
android:orientation="vertical">
<Button
android:id="#+id/favButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="4dp"
android:background="#drawable/ic_favorite_black_12dp"
/>
</LinearLayout>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
Finally here's the 2nd fragment where I want to recieve the data
Favorite.java
public class Favorite extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_favorite, container, false);
favText = v.findViewById(R.id.tv_recycler_item_1);
return v;
}
protected void displayReceivedData(String message)
{
Toast.makeText(getContext(),"rec:" + message,Toast.LENGTH_SHORT).show();
}
}
fragment_favorite.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/favFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Favorite">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_scrolling"
android:layout_width="match_parent"
android:layout_height="180dp"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="#drawable/bg_red" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/Widget.AppCompat.PopupMenu.Overflow" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
>
<TextView
android:id="#+id/txtData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="548dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/recycler_view_recycler_view"
app:layout_constraintStart_toStartOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view_recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="382dp"
android:layout_marginEnd="344dp"
android:layout_marginRight="344dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
</android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
Let me know if you need more info. thanks in advance :)
you can pass data between fragment by putting as argument in bundle like following:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
For retrieving you can do following
Bundle bundle = this.getArguments();
if (bundle != null) {
int myInt = bundle.getInt(key);
}
On my view best way of communication is by using EventBus between Activity-fragment, fragment-fragment, Activity-Activty, very easy and less complicated
Here is an Example
Create a model of what you want to share, so here is model for sending string declare the string variable use constructor and getter for setting and getting message
public MessageEvent(String Message)
{
this.msg=msg;
}
public String getMsg() {
return msg;}
Now in your fragment 1 post the message before that register eventbus on OnAttach and deregister it in OnDettach
EventBus.getDefault().post(new MessageEvent("My Message));
In Fragment 2 get the message in OnEvent Method(even in this fragment don't forget to register and deregister Event Bus)
#Subscribe
public void onEvent(MessageEvent event) {
this.msg=event.getMsg();
callTheMethodToDoYourOperation(msg);
}
This a basic example, but check about event bus before using this and moreover in both fragment you require to Register, deregister and subscribe onevent, and if this is one way communication let onEvent be empty
Hope this helps
The NullPointerException occurred because your Fragment is not initialized yet, so before interacting with is make sure you check is it initialized and visible or not.
if (f!= null && f.isVisible()) {
f.displayReceivedData(message);
}
You can also use Bundle to pass data between Fragment too.
Note: Before posting question understand the error and try to debug the root cause of the error. You'll definitely solve it on your own.
Happy coding :)
You are getting Null pointer on method where you receive data, that fragment instance is null. Favorite f is null.
Create one instance if that fragment and then call .replace
The onViewCreate method of Chapter1Fragment class (extending from android.app.Fragment) is returning an object of a class which is subclass of android.opengl.GLSurfaceView
This fragment appears fine on the activity. But the problem is that the drawer navigation view does hides behind this fragment. Please suggest how the drawer menu can be fixed?
here is the code of onViewCreate
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
Bundle savedInstanceState) {
int chapterNumber = 1;
getActivity().setTitle(R.string.txt_chap1);
mPageFlipView = new PageFlipView(getActivity(), chapterNumber);
mGestureDetector = new GestureDetector(getActivity(), this);
mPageFlipView.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
mPageFlipView.onFingerUp(motionEvent.getX(), motionEvent.getY());
return true;
}
return mGestureDetector.onTouchEvent(motionEvent);
}
});
return mPageFlipView;
}
There is another Fragment HomeFragment which invokes the following code to make Chapter1Fragment appear
Chapter1Fragment fragment = new Chapter1Fragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frameLayout, fragment);
fragmentTransaction.commit();
Here is the xml file that is passed to setContentView() of MainActivity's onCreate()
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
Here is the app_bar_main.xml from layout directory
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="viento.com.bookapp.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
Here is the content_main.xml from layout directory
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior"
/>
I have a MainActivity XML that contains a bottomNavigationView (bar) with 5 tabs. Each tab calls a different fragment. Switching from a fragment with a collapsing toolbar in its XML (labelled A in picture) to a fragment with a plain fragment (labelled B in picture) causes the bottomNavigationView (bar) to hide partially off the screen.
Is there a way of preventing this?
Screen with fragment containing collapsing toolbar.
Screen of another tab with a plain fragment.
Fragment Class containing code for collapsing toolbar
public class Profile extends Fragment {
public Profile() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//setHasOptionsMenu(true);
View rootView = inflater.inflate(R.layout.fragment_profile, container, false);
Toolbar toolbar = rootView.findViewById(R.id.toolbar);
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
CollapsingToolbarLayout collapsingToolbar = rootView.findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("test");
return rootView;
}
Corresponding xml containing collapsing toolbar code
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="180dp"
android:theme="#style/ThemeOverlay.AppCompat.Dark">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ani_dog_one"
android:contentDescription="whut"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Plain fragment class
public class Review extends Fragment {
public Review() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_review, container, false);
//setHasOptionsMenu(true);
return rootView;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.search_bar_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
XML for plain fragment class contains just a plain FrameLayout
MainActivity
public class MainActivity extends AppCompatActivity {
private Intent intent;
private android.support.v4.app.FragmentManager manager;
private android.support.v4.app.FragmentTransaction transaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = getSupportFragmentManager();
transaction = manager.beginTransaction();
Discover discoverFragment = new Discover();
transaction.replace(R.id.container, discoverFragment, discoverFragment.getTag()).commit();
setupBottomNavigationView();
}
private void setupBottomNavigationView() {
BottomNavigationViewEx bottomNavigationViewEx = (BottomNavigationViewEx) findViewById(R.id.bottom_navigation);
BottomNavigationViewHelper.setupBottomNavigationView(bottomNavigationViewEx);
BottomNavigationViewHelper.enableNavigation(this, bottomNavigationViewEx);
}
public void goToOptions(MenuItem menu) {
intent = new Intent(this, Options.class);
overridePendingTransition(R.anim.left_in, R.anim.right_out);
startActivity(intent);
}
}
XML for MainActivity
<LinearLayout 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:orientation="vertical"
tools:context="com.example.android.project_qwer.MainActivity">
<!-- main fragments goes here -->
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<!-- bottom navigation view -->
<com.ittianyu.bottomnavigationviewex.BottomNavigationViewEx
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?android:attr/windowBackground"
app:menu="#menu/bottom_navigation_menu" >
</com.ittianyu.bottomnavigationviewex.BottomNavigationViewEx>
</LinearLayout>
Try to remove
android:fitsSystemWindows="true"
on your CollapsingToolbarLayout.
try
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
when you switch to tab with collapsing toolbar and
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
when switch to another
Try to put
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
</android.support.design.widget.CoordinatorLayout>
as the root of all the other fragments you are loading from the BottomNavigationView.
If you use a custom toolbar in the profile fragment,you put this code to onCreateView method:
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
I had the same problem and this was solved.
Remove android:fitsSystemWindows="true"
from root CoordinatorLayout.
Right now my app works fine at regular screen.
I am having a tough time figuring out how I can manage my current UI to handle the two panel layout.
Right now my DetailActivity has some UI elements to load, 3 fragments on separate tabs, controls what each FAB does, FAB animation and a fragment page adapter for the tab layout.
What should I do to manage all of these elements and logics in a separate class and also in the main activity for the two pane layout?
Here is my Main Activity
public class MainActivity extends AppCompatActivity {
public static boolean TWO_PANE;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.movie_detail_container) != null) {
// The detail container view will be present only in the large-screen layouts
// (res/layout-sw600dp). If this view is present, then the activity should be
// in two-pane mode.
TWO_PANE = true;
if (savedInstanceState == null) {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
}else{
TWO_PANE = false;
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, new FragmentMain())
.commit();
}
Fragment Main displays a movie grid layout, when clicked if it's regular phone open another activity, otherwise the movie details should display at the right corner.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Defines the xml file for the fragment
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
imageAdapter = new ImageAdapter(getContext());
gridView = (GridView) rootView.findViewById(R.id.gridView);
gridView.setAdapter(imageAdapter);
//Start DetailActivity with the movie details.
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
if (MainActivity.TWO_PANE){
Bundle bundle = new Bundle();
bundle.putParcelable(Constants.BUNDLE_CONSTANT, mMovieElements.get(position));
FragmentDetail fragment = new FragmentDetail();
fragment.setArguments(bundle);
getChildFragmentManager()
.beginTransaction()
.replace(R.id.movie_detail_container, fragment)
.addToBackStack(null)
.commit();
}else{
//Starting detail activity
Intent intent = new Intent(getContext(), DetailActivity.class);
intent.putExtra(Intent.EXTRA_TEXT, mMovieElements.get(position));
startActivity(intent);
}
}
});
return rootView;
}
land\Activity-main:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
tools:context=".ui.ui.MainActivity">
<!--
This layout is activity_main two-pane layout for the Items master/detail flow.
-->
<FrameLayout
android:id="#+id/container"
class = "com.joaonogueira.nmovies.ui.ui.FragmentMain"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
tools:layout="#android:layout/list_content" />
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:name="com.joaonogueira.nmovies.ui.ui.FragmentDetail"
android:layout_width="0dp"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:layout_weight="4"
android:id="#+id/movie_detail_container"
tools:context="com.joaonogueira.nmovies.ui.ui.DetailActivity">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:expandedTitleGravity="center"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="#dimen/app_bar_height"
android:id="#+id/posterImage"
android:background="#drawable/nopicture"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/MovieContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/fab_margin"
android:src="#android:drawable/btn_star_big_off"
app:layout_anchor="#id/app_bar"
app:layout_anchorGravity="bottom|end"
app:backgroundTint="#color/colorPrimaryDark" />
</android.support.design.widget.CoordinatorLayout>
My Fragment Detail doesn't start, I am getting the following error:
No view found for id 0x7f0c0070 (com.joaonogueira.nmovies:id/movie_detail_container) for fragment FragmentDetail{1b71bc14 #0 id=0x7f0c0070 bundle}
You are trying to replace a fragment from the fragment itself
getChildFragmentManager()
.beginTransaction()
.replace(R.id.movie_detail_container, fragment)
.addToBackStack(null)
.commit();
But since movie_detail_container is not present in the fragment view and is a part of the activity layout instead, hence you are getting that error.
What you need to do is to have a listener interface implemented in your activity and make your fragment listen to that. Finally, you invoke that listener to make your activity replace a new fragment.
If you don't know how to do that read this.