Sub menu in navigation drawer - android

I'm trying to find solution how to create sub menu in navigation drawer. I will be the best to show example from iOS app video
I dont see any methods in navigation drawer documentation to do such layout animations. I will appreciate any help

there is not such concept called sub menu in navigation drawer on the android SDK.
but there are also good news - since Navigation Drawer is eventually layout container - nothing stops you from host inside of it any view or nested layout container you desire instead of host inside of it only ListView , and therefore - you can use also Fragments
if you'll do that - you could perform fragment transactions between them to swipe to another fragment representing the sub menu... also you'll get "for free" the fragment transaction animation, if you'll set it to use one.
each fragment would show ListView (or whatever..) representing different menu screen
add to it you own UI back button header and implement the onClick callback to perform fragment transaction to the "main menu" fragment, and you've got exactly what you want.
this is how your main activity UI xml layout file should look like:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<FrameLayout android:id="#+id/left_drawer_layout_fragment_conatiner"
android:layout_width="240dp"
android:layout_height="match_parent"
android:background="#111"/>
as you see, I replaces the traditional navigation drawer ListView with a FrameLayout. the left drawer can be replaced with any other view or custom component you want, and can act also as fragment container.
EDIT
#Meryl requested from me to show based on the documentation example how I use Fragment as drawer menu. so, assuming you want that your menu would look exactly like the documentation example (which is not must at all because you can make any UI you wish..) this would be the way to translate it into Fragment:
the fragment_menu.xml layout file:
<ListView android:id="#+id/list_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
the FragmentMenu java class:
public class FragmentMenu extends Fragment {
private ListView mListView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_menu, null);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mListView = (ListView)view.findViewById(R.id.list_view);
// Set the adapter for the list view
mListView.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mPlanetTitles));
// Set the list's click listener
mListView.setOnItemClickListener(new DrawerItemClickListener());
}
}
attaching the FragmentMenu to the Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView...
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.left_drawer_layout_fragment_conatiner, new FragmentMenu());
.commit();
}
all the rest should stat almost the same.. and of course - the code in the documentation that creates the menu list and setting the adapter in the activity is not necessary anymore, because it's implemented inside the fragment instead.

Related

How to replace parent fragment view with a child fragment's view?

I'm looking for some help in Android studio with replacing a parent fragment's view with the view of a child fragment when a view in the parent fragment is clicked. Thank you in advance for your help.
Right now I have a parent fragment which is a chat list, and a child fragment (the chat screen) that shows up when you click on an element of the chat screen (i.e. a button). The chat list looks like this:
<FrameLayout 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"
tools:context="com.example.myapplication.ChatListFragment">
<!-- Empty Container for Fragment to Live in -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/chatListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/moonstone">
</ListView>
</FrameLayout>
I have set the onClickListener for the chatListView as follows:
_chatListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String chatName = _chatListAdapter.getItem(i).getChatTitle();
openChatScreen(chatName);
}
});
And the openChatScreenWindow() looks like this:
private void openChatScreen(String chatName)
{
_fragmentManager = getChildFragmentManager();
Log.i(CHAT_LIST_TAG, "starting chat screen fragment");
FragmentTransaction fragmentTransaction = _fragmentManager.beginTransaction();
ChatScreenFragment chatScreenFragment = ChatScreenFragment.newInstance(chatName);
fragmentTransaction.add(R.id.fragment_container, chatScreenFragment);
fragmentTransaction.addToBackStack(GlobalConstants.OPEN_CHAT_WINDOW_FRAGMENT_STRING + chatName);
fragmentTransaction.commit();
}
However, when I run this code, the child fragment is obscured, because both the frame layout (the view that the fragment is displayed in) and the chatListView have their widths and heights set to match_parent (I figured this out by testing the height and width of the chat list as 200dp, and I was able to see the child fragment behind it).
Is there a simple way to get the fragment to replace the chatListView whenever it is loaded?
For example, is there a way to change this view:
To this one:
... when an element in the chat list (the first one) is clicked?
I was thinking of changing the list view's visibility to invisible and visible based on whether the fragment is loaded, but that seems like a headache.
Please let me know what you think, thank you!
First off most modern way of managing fragments is - Navigation component
According your approach - you are adding child fragment on top of the prev fragment with fragmentTransaction.add, you can use fragmentTransaction.replace instead
Also, you might want to set child fragment background to solid color - to hide previous fragment, if you use this method - make child's fragment root clickable - to prevent fragments click through.
My recommendation - spend more time on learning Navigation component

dynamically change the drawer layout

I have this situation: when launching the app, the first fragment (A) displayed has a list of some users. When clicking a user, another fragment (B)is displayed and, together, the drawer menu will be different for each user.
As you can see, I can NOT set up the DrawerLayout when launching the app (the main activity or Launcher) since I don't have the data for the listView yet, but have to set it up when clicking a user in the list in fragment A after the app finishes launching (That's when I can retrieve the data for the listView of the drawer menu, which is indicated by the id: fragment_drawer in below xml file).
Here's the xml file for "MainActivity":
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- The main content view -->
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer, listView is inside MyDrawerFragment's layout-->
<fragment android:id="#+id/fragment_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="mypackage.com.MyDrawerFragment"
tools:layout="#layout/drawer_layout" />
</android.support.v4.widget.DrawerLayout>
How can I achieve the goal in fragment B? Is this achievable at all in fragment B?
If not possible doing this in fragment B, I am thinking to launch a second activity, say Activity2, and the above xml layout file will be applied to this new activity, when clicking the user in fragment A, I just keeps doing this: closing the existing Acitvity2 by calling finish() and create a new Activity2 instance with new data for drawer menu? Is this approach feasible at all?
Any hints are highly appreciated!
Thanks,
Shawn
I had to do an app where I had to make an Activity with 4 fragments and a ViewPager, where only in 2 I would open a different Drawer.
The Activity's layout must contain the DrawerLayout*, but since the Drawer itself depends on which Fragment I'm on, I figured that it should be the Fragment the one in charge of rendering (or not) the Drawer.
*If the Activity doesn't contain the DrawerLayout, it wouldn't be displayed filling the whole screen!
I did something like this, though it does need some refactoring and clean up :)
Working on the idea that the Fragment is in charge of rendering the Drawer, but it is the Activity the one that has access to it, I made two interfaces to communicate Fragment and Activity:
/**
* should be implemented by any fragment interested in communicating
* with a {#link FragmentListener} Activity
*/
public interface ActivityListener {
/**
* called from {#link FragmentListener} requestOpenDrawer
* the fragment is in charge of rendering its drawer's layout
*/
public void renderDrawer(DrawerLayout mDrawerLayout,
NavigationView viewById, Activity activity);
}
-
/**
* used to communicate FROM fragments, to its parent Activity
* implemented by {#link MainTabbedActivity}
*/
public interface FragmentListener {
/**
* call from a fragment to request opening the drawer
* note that if the drawer isn't opened by the activity,
* it wouldn't cover the whole screen
*/
void requestOpenDrawer(Fragment requester);
void requestCloseDrawer();
DrawerLayout getDrawerLayout();
}
Implementation
#Override
public void requestOpenDrawer(Fragment requester) {
mDrawerLayout.openDrawer(Gravity.RIGHT); //Edit Gravity.End need API 14
if (requester instanceof ActivityListener) {
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
//let fragment render the drawer
((ActivityListener) requester).renderDrawer(mDrawerLayout, navigationView, this);
}
}
-
#Override
public void renderDrawer(DrawerLayout mDrawerLayout, NavigationView viewById, Activity activity) {
View child = activity.getLayoutInflater().inflate(R.layout.credit_fragment_drawer, null);
navigationView.addView(child);
}
Layouts
Both the Activity layout and the Fragments layout don't have anything more than the standard Drawer implementation:
Activity layout with Drawer:
<?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/main_tabbed_drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:openDrawer="right">
<include
layout="#layout/activity_main_tabbed_content"
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="right"
android:fitsSystemWindows="true" />
</android.support.v4.widget.DrawerLayout>
Where activity_main_tabbed_content is whatever the content you want to put in the Activity.
The fragments really don't have anything more than a common Fragment.
Example:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- whatever views you want -->
</RelativeLayout>

ActionBar Navigation Tabs - Main Activity Layout for Tab?

I have great problems getting the Navigation Tabs work. I am aware of this guide http://developer.android.com/guide/topics/ui/actionbar.html#Tabs
but I have problems understanding the article. It says the following:
To get started, your layout must include a ViewGroup in which you place each Fragment associated with a tab. Be sure the ViewGroup has a resource ID so you can reference it from your code and swap the tabs within it. Alternatively, if the tab content will fill the activity layout, then your activity doesn't need a layout at all (you don't even need to call setContentView()). Instead, you can place each fragment in the default root view, which you can refer to with the android.R.id.content ID.
As I don't use a Fragment for my Main Layout, but for others, I think the "alternative" way is right for me (I would like Tab 1 to be the Main Layout I have right now and then 2 and 3 to be my fragments), but I don't know how to accomplish this. Can someone maybe help out on this?
I was able to set up the tabs and the TabListener, so that is not the problem. The problem is that the first tab is NOT supposed to be a fragment, but my main activity layout! This is where I need help!
I did try to use my main activity-layout for a fragment, but for some reason if I click that tab, the tab changes but the screen stays white. I cannot see my fragment view.
The old code was:
mListView = (ListView) findViewById(R.id.list_view);
mListView.setAdapter(mAdapter);
mListView.setTextFilterEnabled(true);
and I've changed it in the fragment to:
View view = inflater.inflate(R.layout.list, container, false);
mListView = (ListView) view.findViewById(R.id.list_view);
mListView.setAdapter(mAdapter);
mListView.setTextFilterEnabled(true);
// do stuff here //
return view;
and this is list.xml:
<FrameLayout xmlns:android:="http://schemas.android.com/apk/res/android"
android:id="#id/main_fragment"
android:layout_width="match_parent"
android:layout:height=match_parent">
<ListView android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout:height=0dp"
android:layout_weight="1"
android:layout:marginTop="20dp"
android:descendantFocusability="blocksDescendants"/>
</FrameLayout>
how come I cannot see anything?
Solved: This was because I set the height to 0dp.
Please update your code by this:
<FrameLayout xmlns:android:="http://schemas.android.com/apk/res/android"
android:id="#+id/main_fragment"
android:layout_width="match_parent"
android:layout:height=match_parent">
<ListView android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:descendantFocusability="blocksDescendants"/>
</FrameLayout>

How do I swap fragments in and out of my app?

I have been following the tutorial here:
And this code here has been confusing me:
/** Swaps fragments in the main content view */
private void selectItem(int position) {
// Create a new fragment and specify the planet to show based on position
Fragment fragment = new PlanetFragment();
Bundle args = new Bundle();
args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
fragment.setArguments(args);
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
// Highlight the selected item, update the title, and close the drawer
mDrawer.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawer);
Right now my app runs and looks great, but when you press on the buttons in the navigation drawer, nothing happens. I need to figure out how that if a user presses one button, it swaps in a new FrameLayout. Also another question: I have this in my activity_main.xml layout:
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:keepScreenOn="true"
>
</ListView>
</FrameLayout>
<!-- android:layout_gravity="start" tells DrawerLayout to treat
this as a sliding drawer on the left side for left-to-right
languages and on the right side for right-to-left languages.
The drawer is given a fixed width in dp and extends the full height of
the container. A solid background is used for contrast
with the content view. -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
I'm not entirely sure if I should have my list view with the content in it yet (the ListView inside of the FrameLayout). I tried making its own xml layout but when I refrenced it to inflate the ListView it didn't work. So do i set up a separate 'xml' file for each frame? If so, how do I swap in that fragment based on what button is clicked? Thanks for your time and help!
EDIT!!
THIS IS THE SELECTITEM METHOD
private void selectItem(int position) {
Log.i("MainActivity", "selectItem()" + position); //this gets called successfully
//not sure if this equals() thing is the best way to do this
if("Stuff".equals(getListView().getItemAtPosition(position))){
Log.i("MainActivity", "getItemAtPosition()-Stuff" + position); //this doesn't get called
mDrawerList.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}else if("Stuff2".equals(getListView().getItemAtPosition(position))){
Log.i("MainActivity", "getItemAtPosition()-Stuff2" + position); //this also doesn't get called
mDrawerList.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
Intent openHelpAvtivity = new Intent("com.schrodingerscat.hh.math.glossary.THEOREMSLIST");
startActivity(openHelpAvtivity);
}
Have you tried stepping through it with a debugger? Is selectItem() getting called? If not, make sure that you set the OnClickListener correctly.
You don't need separate XML files for each frame. (What do you mean by frame? Fragment? I'm assuming so.) The whole point is that you can create a new fragment and use setArguments() to set what it displays. The list view should have its data populated with the following code, as provided:
mPlanetTitles = getResources().getStringArray(R.array.planets_array);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
// Set the adapter for the list view
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPlanetTitles));
Try downloading the full example code (http://developer.android.com/shareables/training/NavigationDrawer.zip) and see what you're doing differently. I think that this example is meant to be downloaded, not reconstructed: the tutorial page doesn't quite include all the code that you need.
I fixed it! Yay! Thanks to #bee for the enlightenment! All i had to do, instead of using getListView(), I did this instead: if("Stuff".equals(mDrawerList.getItemAtPosition(position))){} and that finally worked!

Replace fragment in tab

I am trying to implement an Action Bar with Tabs navigation set using ActionBarSherlock. I currently have three tabs which I can switch between ok. On one of my tabs I am implementing a ListView. When one of the items in the list is selected I want to replace the list with another fragment which will be a detail view of the selection.
When I call the FragmentTransaction.replace method with the new detail fragment I can see the new fragment appear but it overlaps the ListView, meaning I can see both fragments. Is this kind of navigation possible using the ActionBar tabs navigation, or am I on completely the wrong lines. I feel I am missing something really fundamental here.
I have a SherlockFragmentActivity which is implementing a TabListener to handle moving between tabs. The fragment hosting the ListView inherits from SherlockListFragment and I have attached a OnItemClickListener to respond to the tap and to replace the fragment. I am using this code
numbersList.setOnItemClickListener(new ListView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View v, int i, long l) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(android.R.id.content, new NumberSelectedNavigationMenuFragment());
ft.commit();
}
});
The fragment which is replacing the ListView is currently just a basic LinearLayout with a TextView.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Test"
android:id="#+id/textView"/>
</LinearLayout>
Any help appreciated with this as I am well and truly stuck ...

Categories

Resources