Is it possible to change the transition effect from opening a fragment from a drawerlayout with the android navigation component. There is nothing in the android docs.
Sarah! Yes, it is possible. You can add your custom listener to handle navigation item selection and add animation there. I had to add one myself, for other purposes, but it definitely fits as a solution for your task.
How to:
Add layout with drawer. Example:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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">
<!-- Other views can be added here, or below -->
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/menu_for_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
Find NavigationView by ID and assign it to a variable private NavigationView navigationView in your activity, that you may extract by using findViewById(R.id.nav_view). This step is optional. You may find the view and assing naviation item selection listener without holding a reference to NavigationView;
Set navigation item selection listener:
navigationView.setNavigationItemSelectedListener(menuItem -> {
#IdRes
int id = menuItem.getItemId();
NavOptions.Builder optionsBuilder = new NavOptions.Builder();
switch (id) {
case R.id.first_menu_item_id: {
// Lets assume for the first menu item navigation is default
optionsBuilder
.setEnterAnim(R.anim.nav_default_enter_anim)
.setExitAnim(R.anim.nav_default_exit_anim)
.setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
.setPopExitAnim(R.anim.nav_default_pop_exit_anim);
}
break;
case R.id.second_menu_item_id: {
// Lets assume for the second menu item navigation is missing
// empty here
}
break;
case R.id.thrid_menu_item_id: {
// Lets assume for the third menu item navigation is custom
optionsBuilder
.setEnterAnim(R.anim.slide_in_right)
.setExitAnim(R.anim.slide_out_left)
.setPopEnterAnim(R.anim.slide_in_left)
.setPopExitAnim(R.anim.slide_out_right);
}
break;
}
navController.navigate(id, null, optionsBuilder.build());
// Do not forget to close the drawer
// drawer.closeDrawers();
return true;
});
This should help! Any thoughts and questions are welcome!
In case you are interested in animations mentioned in example:
slide_in_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
slide_in_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
slide_out_left.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="-100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
slide_out_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="300"/>
</set>
Update (28 March 2020)
In case this solution doesn't work with the Drawer Menu try to use it with the following code.
Note that I placed setNavigationItemSelectedListener call at the end of the method due to NavigationUI functions sometimes settings it's own listener. That could also be the cause of problem.
There is a lot going on behind NavigationUI functions and if something doesn't work right check out implementation of the functions you use.
private void setupNavigation() {
// Set custom toolbar as action bar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
// Setup navigation with toolbar and drawer
NavController navController = Navigation.findNavController(this, R.id.main_nav_host_fragment);
/* The set of destinations by id considered at the top level
of your information hierarchy. The Up button will not be displayed
when on these destinations. */
Set<Integer> set = new HashSet<>(Arrays.asList(R.id.first_fragmentId_from_nav_graph, R.id.second_fragmentId_from_nav_graph, R.id.third_fragmentId_from_nav_graph));
/* Configuration options for {#link NavigationUI} methods that interact with implementations of the
app bar pattern */
AppBarConfiguration configuration = new AppBarConfiguration.Builder(set).setDrawerLayout(drawer).build();
NavigationUI.setupWithNavController(toolbar, navController, configuration);
NavigationUI.setupWithNavController(navigationView, navController);
NavigationUI.setupActionBarWithNavController(this, navController, configuration);
// And here you set the listener.
navigationView.setNavigationItemSelectedListener(...);
}
There are multiple calls to NavigationUI functions like setupWithNavController and setupActionBarWithNavController. The reason is that behind each one of them is added one more destination changed listener to navigation controller. See addOnDestinationChangedListener for more information about the listener.
First call adds new ToolbarOnDestinationChangedListener(toolbar, configuration);
Second call adds custom implementation of NavController.OnDestinationChangedListener that updates your navigation view in drawer correctly;
Third call adds new ActionBarOnDestinationChangedListener(activity, configuration).
This configuration allows me to use a single application on a tablet with a Master-Detail pattern and on the phone as a usual application with Drawer Menu.
Referenced string resources are just:
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
But they are required for accessibility. It's very good to translate them if you support multiple languages. Basically anything used for accessibility is generally good to translate.
There is a simpler way. Internally NavigationUI builds the NavOptions like this:
if (navController.getCurrentDestination().getParent().findNode(item.getItemId())
instanceof ActivityNavigator.Destination) {
builder.setEnterAnim(R.anim.nav_default_enter_anim)
.setExitAnim(R.anim.nav_default_exit_anim)
.setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
.setPopExitAnim(R.anim.nav_default_pop_exit_anim);
} else {
builder.setEnterAnim(R.animator.nav_default_enter_anim)
.setExitAnim(R.animator.nav_default_exit_anim)
.setPopEnterAnim(R.animator.nav_default_pop_enter_anim)
.setPopExitAnim(R.animator.nav_default_pop_exit_anim);
}
You can just create these directories yourself and override the defaults. In my case I had to create the animator folder (not anim!) in /res/ and put 4 new animation files with these names in it. But maybe try both folders to be sure.
At the moment it works perfectly in a MaterialComponents Theme: the selected drawer item still get's highlighted and the appbar animation is still working too (unlike with some other methods).
Related
I'm using android Navigations for handeling my backstack.
I want to create a transition from the fragment data to fragment map.
Right now I have the problem, when I execute a Navigation Event from a button in my app like this:
NavController navController = Navigation.findNavController(view);
navController.navigate(LoadDataFragmentDirections.actionDataToMap());
I get navigated to my destination map. But I can't click data in my navigation menu anymore.
If I backpress, my view goes back to data like intended.
An then, the button data get's also clickable in the menu again.
Here is my navigation graph.
<?xml version="1.0" encoding="utf-8"?>
<navigation 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/mobile_navigation"
app:startDestination="#id/navigation_load_data">
<fragment
android:id="#+id/navigation_load_data"
android:name="com.example.axistracker.ui.app.open_data.LoadDataFragment"
android:label="#string/open_file"
tools:layout="#layout/fragment_load_data">
<action
app:launchSingleTop="true"
app:popUpToInclusive="true"
android:id="#+id/action_data_to_map"
app:destination="#id/navigation_map" />
</fragment>
<fragment
android:id="#+id/navigation_map"
android:name="com.example.axistracker.ui.app.map.MapFragment"
android:label="#string/map"
tools:layout="#layout/fragment_map" />
</navigation>
It feels like, I don't replicate the same behaviour with "navController.navigate(...)" as if I would just click in my menu.
I'm using:
implementation 'androidx.navigation:navigation-fragment:2.5.0'
implementation 'androidx.navigation:navigation-ui:2.5.0'
I'm happy about any ideas!
PatPat
I'm creating android app which contain bottom navigation bar with 4 buttons. I would like to Preselect the 3rd button when initially app is launches rather then the First tab by which is selected by Default. I have used replace frgment to load Third Fragment initially with below code
secondFragment = new second();
replaceFragment(secondFragment);
But still, the first tab is active by default instead of the third although third fragment loads successfully
Here is the xml file from menu
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/bottom_action_home"
android:icon="#drawable/ic_visibility_black_24dp"
android:title="I"
app:showAsAction="always|withText" />
<item
android:id="#+id/bottom_action_notif"
android:icon="#drawable/ic_visibility_black_24dp"
android:title="II"
android:checked="true"
app:showAsAction="always|withText" />
<item
android:id="#+id/bottom_action_account"
android:icon="#drawable/ic_visibility_black_24dp"
android:title="III"
app:showAsAction="always|withText"/>
<item
android:id="#+id/bottom_action_chat"
android:icon="#drawable/ic_visibility_black_24dp"
android:title="IV"
app:showAsAction="always|withText"/>
</menu>
and activity xml file is
<android.support.design.widget.BottomNavigationView
android:id="#+id/mainBottomNav"
android:background="#color/colorblog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/bottom_menu"
android:layout_alignParentBottom="true"/>
and my java file is
mainbottomNav = findViewById(R.id.mainBottomNav);
BottomNavigationViewHelper.removeShiftMode(mainbottomNav);//disable BottomNavigationView shift mode
// FRAGMENTS
mainbottomNav.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.bottom_action_home:
return true;
case R.id.bottom_action_notif:
return true;
case R.id.bottom_action_account:
return true;
case R.id.bottom_action_chat:
default:
return false;
}
}
});
I would like to have Third Button active when application is launched i.e case R.id.bottom_action_account:
Thanks in advance.
Add this line to your code
mainbottomNav.setSelectedItemId(R.id.bottom_action_account);
If you want that part of your navigation bar to be highlighted then use as mayank said:
navBar.setSelectedItemId(R.id.menuItem);
but if you're talking about when the activity starts, either change your setContentView to the correct activity, or use setActivity to complete change to a new intent/class.
In your Java file, you can add code that looks like so:
mainBottomNav.setSelectedItemId(R.id.bottom_action_account);
You can add this to your onCreate at the end so that way it is made after the view is made so the end-user will see the third tab selected.
Cheers.
I'm working on the navigation drawer where i want to show details of the user in the navigation drawer like profile,contact us,logout etc if he is not logged in then i want to show only one item which is have be login on it nothing else must present in it i will be using the JSON for Authenticate the login Please refer the pics friends
Your question is broad. However to achieve what you want, you will probably want to use the MaterialDrawer library. Just check their README it's very simple to use.
The "login" functionality you are looking for will be in the AccountHeader of your drawer, for instance:
// Create the AccountHeader
AccountHeader headerResult = new AccountHeaderBuilder()
.withActivity(this)
.withHeaderBackground(R.drawable.header)
.addProfiles(
new ProfileDrawerItem().withName("Mike Penz").withEmail("mikepenz#gmail.com").withIcon(getResources().getDrawable(R.drawable.profile))
)
.withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() {
#Override
public boolean onProfileChanged(View view, IProfile profile, boolean currentProfile) {
return false;
}
})
.build();
//Now create your drawer and pass the AccountHeader.Result
new DrawerBuilder()
.withAccountHeader(headerResult)
//additional Drawer setup as shown above
...
.build();
(Snippet taken from the official README, again: every thing is there).
Your question is broad but if you are using navigation view you can change header view and drawer items using
navigationView.inflateHeaderView(layoutResId);
navigationView.inflateMenu(menuResId);
Navigation view is provided by android. So it is not a third party library and it is simple to integrate.
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- your content layout -->
<android.support.design.widget.NavigationView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/drawer_header"
app:menu="#menu/drawer"/>
</android.support.v4.widget.DrawerLayout>
You can find complete information here - http://android-developers.blogspot.in/2015/05/android-design-support-library.html
http://developer.android.com/reference/android/support/design/widget/NavigationView.html
When using the drawer layout is there a way to overlay the drawer view over the action bar? I do not want to hide the action bar when the drawer is shown. I want the action bar to simply stay put, but be sent to the background. An example of this is the iOS Play Music app...
My current implementation hides and shows the action bar when the drawer state changes, but I do not like this user experience.
public void onDrawerClosed(View view) {
getActionBar().show();
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
getActionBar().hide();
invalidateOptionsMenu();
}
I searched the web in order to find any good solution for this problem and haven't found. So I did a trick that did this.
First of all we need to request action bar overlay feature. So in onCreate() of your activity, before setContntView() call: requestWindowFeature(com.actionbarsherlock.view.Window.FEATURE_ACTION_BAR_OVERLAY);
It will make everything including navigation drawer draw behind action bar. We don't need this, so we need to set the top margin of our FrameLayout which hosts our fragments in the activity with the exact height of the action bar. In the layout file of the activity we need to do the following:
<!-- Framelayout to display Fragments -->
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize" />
It will make only navigation drawer appear behind the action bar.
Now we will hide the action bar when the navigation drawer is opened on half, and will show it when the drawer is nearly closed. To do this we need to make the following in the activity:
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
if(slideOffset > 0.5){
actionBar.setBackgroundDrawable(null);
actionBar.hide();
} else {
actionBar.show();
if(slideOffset < 0.1){
actionBar.setBackgroundDrawable(layerDrawable);
}
}
}
As you can see I also change the background drawable of the action bar to make it transparent when before I begin to hide it, and change it back with my custom background when I show it back.
My custom background is a layerListDrawable which is all transparent but have a divider in bottom with some shadow.
And to achieve this I have defined the following layer-list in XML:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:top="0dp" android:left="0dp" android:bottom="0dp" android:right="0dp">
<shape android:shape="rectangle">
<solid android:color="#android:color/transparent"/>
</shape>
</item>
<item android:top="0dp" android:left="0dp" android:bottom="0dp" android:right="0dp">
<shape android:shape="rectangle">
<solid android:color="#afafaf"/>
</shape>
</item>
<item android:top="0dp" android:left="0dp" android:bottom="0dp" android:right="0dp">
<shape android:shape="rectangle">
<gradient
android:angle="270"
android:startColor="#88afafaf"
android:endColor="#33afafaf"
/>
</shape>
</item>
</layer-list>
And to get the background I need from this XML I do the following in the activity:
final ActionBar actionBar = getSupportActionBar();
final LayerDrawable layerDrawable = (LayerDrawable) getResources()
.getDrawable(R.drawable.shadow_divider);
final TypedArray styledAttributes = getTheme().obtainStyledAttributes(
new int[] { R.attr.actionBarSize });
int topOffset = (int) (styledAttributes.getDimension(0, 0));
styledAttributes.recycle();
layerDrawable.setLayerInset(1, 0, topOffset - 3, 0, 2);
layerDrawable.setLayerInset(2, 0, topOffset - 2, 0, 0);
actionBar.setBackgroundDrawable(layerDrawable);
where R.drawable.shadow_divider is the XML layer-list I have defined earlier.
It looks really great! Hope it can help someone.
EDIT
I had a small bug here which can be a reason of a crush sometimes. Here is the fixed code:
`
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
**android:paddingTop="?attr/actionBarSize"** />`
It should be paddingTop not layout_marginTop!
That's the proper effect in Android defaults. If you want to emulate the iOS effect, you'll probably have to do it yourself, because AFAIK the drawer component of the support library doesn't allow such type of configurations.
Anyway, every time a programmer codes a lot just to emulate some fancy (and much probably not worthy) iOS effect in Android, a little cat dies...
I don't think you'll be able to do this with Android's provided Navigation Drawer (without doing something really hacky), since doing this really goes against Android design patterns. If you want a library that does what you're looking for, I've used this library before Android came out with it's own widget, and it does what you're looking for.
I found the answer in my question, also added an example project for reference. You can take a look to see if it works for you.
Android Navigation Drawer on top ActionBar
You can achieve this with ActionBarSherlock.
http://actionbarsherlock.com/
You will be able to do it but the drawer will look so awkward that you will not like it. I had the same requirement and I ended up using Radio Buttons customized to appear as tabs. You can also try hiding the tabs when the drawer opens and vice versa, but that certainly is not what you want here.
You can try to use ViewPager, tabbed indicator such PagerTabStrip and/or TabPageIndicator.
Source.
I have a main.xml layout file and in my Java code, I am doing some calculation taken from the main layout and wanting to display in result.xml layout file. I know I can use the anim folder to hold the animation to slidei n the result layout like the following:
left to right:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
right to left:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700" />
</set>
I was wondering how to implement the above so when the button is clicked on the main layout file, the result layout file slides in from the right. And also if I wanted to go back to the main layout I can press a button (added on result layout) to slide right the main layout file
You can also use this function : overridePendingTransition which can define an animation for the upcoming activity and an other animation for the activity which exit.
Use it like this, in your second Activity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(android.R.anim.slide_out_right, 0);
setContentView(R.layout.myLayout);
first argument is for the animation enter, and 0 is for no animation.
And for an animation when you leave your second activity :
#Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.enterAnim, R.anim.leaveAnim);
}
You can always use default stock animations supplied by Android framework.
Heres an example code:
boolean isFirstXml=evaluatingConditionFunction();
LayoutInflater inflator=getLayoutInflater();
View view=inflator.inflate(isFirstXml?R.layout.myfirstxml:R.layout.myseconxml, null, false);
view.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.slide_out_right));
setContentView(view);
Call this from any of your activity which holds your Parent View.
For custom animations you can visit developer docs. Heres the documentation link.