Navigation Android locking menu - java

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

Related

Android safe args navigate to destination in adapter onClick not working

In my Android (Java) app I'm using safe args with my nav controller to navigate to a detailed screen of the item clicked in my RecyclerView adapter. However, I'm having trouble getting my inner action class to be recognized:
holder.binding.firstItemLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirstFragmentDirections.ActionFirstFragmentToSecondFragment action =
FirstFragmentDirections.actionFirstFragmentToSecondFragment(list.get(position).getId());
Navigation.findNavController(v).navigate(action);
}
});
I get a "Cannot resolve symbol 'ActionFirstFragmentToSecondFragment'" warning.
This is my nav_graph.xml:
<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/nav_graph"
app:startDestination="#id/firstFragment">
<fragment
android:id="#+id/firstFragment"
android:name="com.blah.fragment.FirstFragment"
android:label="FirstFragment">
<action
android:id="#+id/action_firstFragment_to_secondFragment"
app:destination="#id/secondFragment" />
</fragment>
<fragment
android:id="#+id/secondFragment"
android:name="com.blah.fragment.SecondFragment"
android:label="SecondFragment"
tools:layout="#layout/fragment_second" />
</navigation>
I feel like this should work, but it doesn't. I've tried rebuilding, invalidating my cache with restart and closing & restarting Android studio. Does anyone know what I've done wrong or how to fix this?

FragmentManager begin transaction without container id

fragmentManager.beginTransaction().replace(R.id.fragment_container_view,mapFragment).commit();
As we know that, this way we can load or replace Fragment
But
In this snippet we are passing fragment container id.
Is there any way
to load fragment without passing ID or pass FragmentContainerView instead of id
you can use navigation graph action to navigate between fragments with one line of code like that :
Navigation.findNavController(this).navigate(R.id.action_fragment1_to_fragment2)
provided that :
you have a navigation graph that looks like this
<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/nav_graph"
app:startDestination="#id/fragment_1">
<fragment
android:id="#+id/fragment_1"
android:name="Your.Package.Fragment_1"
tools:layout="#layout/fragment_1_layout">
<action
android:id="#+id/action_fragment1_to_fragment2"
app:destination="#id/fragment_2" />
</fragment>
<fragment
android:id="#+id/fragment_2"
android:name="Your.Package.Fragment_2"
tools:layout="#layout/fragment_2_layout">
</fragment>
</navigation>
and you've written the correct code to setup your activity with navigation components.
If you don't know what is navigation components I highly recommend taking the navigation lab on android developers where it should instruct you how to setup your project with it.
Learn Jetpack Navigation | Android Developers (Java)
for more information about navigation components and fragments follow these links and start reading Android Developers Tutorials.
Fragments| Android Developers
Navigation Components | Android Developers

Android Navigation Component with Transition from Drawerlayout

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).

RecyclerView animates items all at once instead of one by one

My Problem
I've been trying to get my Recycler View's items to animate as I scroll down. These items are loaded from a local XML and passed through my custom adapter.
I'm using this library for my adapter animation
I noticed that no matter what I tried, the items would just not animate at all, or they would animate all at once (every item would slide in on screen at the same time).
What I've Tried So Far
Utilizing the library I mentioned, I tried animating items in my RecyclerView.Adapter.
> IndexFragment.java snippet
//Create an adapter
SongAdapter adapter = new SongAdapter(songs, getContext());
//Set adapter
AlphaInAnimationAdapter alphaAdapter = new AlphaInAnimationAdapter(adapter);
alphaAdapter.setFirstOnly(false);
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
This one failed somehow. I also tried the setItemAnimator method which also failed.
recyclerView.setItemAnimator(new SlideInLeftAnimator());
Layout Structure
So I assume it has something to do with my RecyclerView being inside of two NestedScrollView's.
Another person seemed to be having a similar issue
Below are some portions of my layout files
activity_main.xml
....
<!-- Fragment Container -->
<android.support.v4.widget.NestedScrollView
android:id="#+id/contentContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
....
This is where I put my fragments
index_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/nestedScrollView"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v4.widget.NestedScrollView>
This is pretty much my Recyclerview and its parent Nested Scrollview.
item_song.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp">
<!--I have two text views in here. Removed them just for this snippet -->
</LinearLayout>
<!-- This displays a background on each item when I press them AKA touch effects -->
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:clickable="true"
android:background="?android:attr/selectableItemBackground" />
</FrameLayout>
This is the structure of each item in the Recyclerview. I inflate this layout for each item. Pretty straightforward.
Any ideas as to what I could do to solve this issue? Thanks.
So after much testing, I finally came up with a solution that worked.
Change the fragment container in activity_main.xml from NestedScrollView to RelativeLayout or perhaps LinearLayout.
Remove the parent NestedScrollView and keep only the RecyclerView in index_fragment.xml.
Animations now work at last. Yay!
Apparently, it is a bad idea to put your RecyclerView inside of a NestedScrollView.
I read somewhere that because of having to load the proper height of its child layout, the NestedScrollView has to wait for it to completely load, in order to know the total height of the RecyclerView. However, I'm not totally sure if that's the reason, so feel free to correct me.
Hope this helps someone!

Use activity as a dialog

I want to use an activity as a dialog in my android application. Till now, I've used AlertDialogs but I want to make my app more fancy. I've done a lot of research on this but couldn't find a satisfactory answer.
I created a new activity named DialogActivity.java and dialogactivty for the java and xml files respectively.
So, How do I call this activity as a dialog in some other activity?
AND
How do I give this activity a round cornered rectangle dialog shape?
Thanks in advance!
You can set a dialog theme to activity as
<activity android:theme="#android:style/Theme.Dialog" />
and use
<activity android:theme="#android:style/Theme.Holo.Dialog" /> // api level 11 and above
in manifest for the activity required.
You need to start the activity using startActivity(intent)
From the official documentation,
If you want a custom dialog, you can instead display an Activity as a
dialog instead of using the Dialog APIs. Simply create an activity and
set its theme to Theme.Holo.Dialog in the manifest element:
<activity android:theme="#android:style/Theme.Holo.Dialog" >
That's it. The activity now displays in a dialog window instead of
fullscreen.
Use Theme.Dialog for API 10 or lower.
try this :
android:theme="#android:style/Theme.Dialog">
entry in manifest for the activity you required.
#ChinmayDabke To display with rounded corners, you need to create a new shape using xml and set it as the background drawable.. be sure to also set transparency for your activity. For more detailed information on this, there are many up-to-date topics available - I just wanted to give a quick answer to this old post, since you had asked!
My mistake - you don't need to set as Transparent - I meant to say set no Titlebar!
Example:
Create a Shape for the rounded background, inside your res/drawable folder:
shape_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#color/colorOfActivityHere"/>
<corners
android:radius="12dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
Then set the shape as the Background of your activity's parent layout:
layout_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_activity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:background="#drawable/shape_background"
android:orientation="vertical">
...
</LinearLayout>
And in your Activity.java, set no titlebar:
Activity.java
requestWindowFeature(Window.FEATURE_NO_TITLE);

Categories