I'm trying to support back button, while the design on my app is navigation drawer. The problem is the fragments doesn't pushed into backstack, but I solved it:
getFragmentManager().beginTransaction().addToBackStack();
but the problem, is when I'm clicking the back button - the title keep. I solved it too with
getActivity().getActionBar().setTitle(str);
but still, the problem is in the navigation list - on the left side. it doesn't changed appropriate to back button (just stay as it was).
Actually, my question is how can i get backStack top - so than i can easily solve it, or if you have another solution.
Maybe a bit late but still for people who don't know how to it. I think this will solve your problem:
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
public void selectItem(int position) {
listView.setItemChecked(position, true);
String[] simple_array = fragment_items.toArray(new String[fragment_items.size()]);
setTitle(simple_array[position]);
}
public void setTitle(String title){
getSupportActionBar().setTitle(title);
}
so when I click on an item in the listview of the navigation drawer, it calls the function selectItem with the parameter position. In the selectItem method I converted my arraylist to a normal array to set my title. The position in your listview is the same as the positions in your array. So simple_array[0] is equal to you first list item. Hope this helps =)
write the line after setContentView()
getActionBar().setDisplayHomeAsUpEnabled(true);
and use the
#Override
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: {
CommonFunctions.writeLogs(getApplicationContext(), CONFIG, LOGGER,
"onCreateOptionsMenu()" + "home");
finish();
}
break;
}
default:
break;
}
return true;
}
Hope it will solve your problem
Related
simple question which I haven't been able to find an answer to or figure out by myself.
How can I have the NavigationView always start on its "original" scroll position whenever it's open, so the first menu item is always visible regardless of where the scroll position was left previously.
I've tried this without success:
drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
...
#Override
public void onDrawerClosed(View drawerView) {
drawerView.scrollTo(0, 0);
}
...
});
Thanks.
Well after examining the View hierarchy of the NavigationView widget, it's comprised of a NavigationMenuView that extends RecyclerView, so using this I've come up with this shenanigan:
((NavigationMenuView)((NavigationView)drawerView).getChildAt(0)).scrollToPosition(0);
If you want to update the drawer items when user has selected some item in the drawer. Then
you should refresh the adapter for the listview in onItemClick.
call notifydatasetchange() to reflect the changes.
But, if you want if user has selected some item in the list, then on closing of drawer after making selection, you want to update the list, for this case you
Listen for closing of drawer event -
public void onDrawerClosed(View view) {
// refresh adapter and call notify data set change.
}
See this link : https://developer.android.com/training/implementing-navigation/nav-drawer.html
to rest all of items and scrolls
I use recreate() method in onDrawerClosed() or item selected like this:
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle
(Navigation_view.this,drawer_layout, toolbarNavigation,
R.string.openDrawer,R.string.closeDrawer){
#Override
public void onDrawerClosed(View drawerView) {
recreate();
super.onDrawerClosed(drawerView);}
nav_view.setNavigationItemSelectedListener(item ->
{switch (item.getItemId()) {
case R.id.item1: recreate();
break;
return true;
I am using a ToolBar Spinner to switch among the 6 activities of my App. The opening activity, which I call MainView, has only the spinner [plus a help link on the ToolBar action menu]. The user selects from the spinner which of the other 5 activities he wishes to run and when finished uses the ToolBar back button of that activity to return to MainView.
It all works fine except, after returning to MainView from any of the other activities, the name of that activity remains displayed in the Spinner, not MainView as i had expected. Plus, if user wants to return to that same activity he must select any of the others first.
I had thought that when the App returns to MainView using the ToolBar back button it would do so by calling the MainView OnCreate, and the MainView spinner would be recreated thus displaying MainView. But this appears to be not the case.
I have tried a few things including setSelection(0) in onCreate, re-initializing the spinner in onStart and onResume - but none has made a difference. Hope you can help.
xml for spinner ...
<Spinner
android:id="#+id/spinner_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
initialization code for spinner
String[] mainview_names = new String[]
{"MainView", "WebView", "JsoupView", "CodeView", "Connectivity", "FtpView"};
Spinner mainSpinner = (Spinner) findViewById(R.id.spinner_main);
ArrayAdapter<String> adapter = new ArrayAdapter<>
(this,android.R.layout.simple_spinner_dropdown_item, mainview_names);
mainSpinner.setAdapter(adapter);
mainSpinner.setOnItemSelectedListener(new CustomOnItemSelectedListener());
// mainSpinner.setSelection(0);
The Listener ...
public class CustomOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
switch (pos){
case 0: // Main View
break;
case 1: // Web View
BrowseWWW();
break;
case 2: // Jsoup View
LoadHTMLJsoup();
break;
case 3: // Code View
LoadHTMLCode();
break;
case 4: // Connectivity
GetHTMLConn();
break;
case 5: // Ftp View
GetHTMLFtp();
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
}
EDIT: Additional information:
The 5 activities each respond to the back button with code structured like this.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
help.setVisibility(View.GONE);
switch (item.getItemId()){
case android.R.id.home: // up navigation
finish();
return true;
case R.id.load:
// ....
}
return true;
case R.id.Clear
// ...
return true;
}
return false;
}
#Override
public void finish() {
Intent i = new Intent();
i.putExtra("urlKey", url.getText().toString());
i.putExtra("tokenKey", token.getText().toString());
i.putExtra("redirectsKey", HttpURLConnection.getFollowRedirects());
setResult(RESULT_OK, i);
super.finish();
}
Ok the spinner state issue:
Without digging into more of your code, here's my theory:
You're in activity A. You select something in the spinner, say B. Now you're in activity B and activity A is paused retaining state it had -- i.e. it has the item corresponding to B selected in the spinner. When you go back from B, activity A is resumed in that exact state and, of course, still has the B item in the spinner. You can't go to B again right away, because if you re-select B, your select handler will not be called (since there's no change).
The fact that Activity is not destroyed every time is probably what tricked you, that's why you should take a look at google guide on Activities -- it will probably save you a lot of guessing time :)
So, to fix your issue with spinners, you should override the onResume() method of each activity and use it to set the spinner to the state corresponding to that activity -- that's the short version.
Long version is, you're probably going somewhat against the flow using toolbar spinner to navigate between activities.
Navigation can be faster and more intuitive you implement your Web, Jsoup, Code and other top-level views as Fragments (also, this) inside a single Activity, that's exactly what they're for. It'll probably be more user-friendly to use Tabs instead of Spinner.
A'right so here I am making an app with a Navigation drawer list.
Now in general a method is provided to respond to each item selection/click in the list.
The method is--
private void selectItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new CreateFragment();
break;
case 1:
fragment = new ReadFragment();
break;
case 2:
fragment = new HelpFragment();
break;
default:
break;
}
Now I want to respond to the item click in the drawer list according to something else rather than just its position such as its title or image id. By far, I've failed to achieve this...can someone help???
Right now I'm using the navigation list code from this website:
Android Custom Navigation Drawer
This is the function that calls SelectItem.
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
SelectItem(position);
}
All you need to do is write a new function and put it where SelectItem() is. You can pass your new function the view, and lookup it's title. Example:
public void example(View v){
TextView tv = (TextView) v.findViewById(R.id.exampleId);
String title = tv.getText().toString();
//Do something with title..
}
I'm developing an application which uses the navigation drawer pattern (With DrawerLayout).
Each click on a drawer's item, replaces the fragment in the main container.
However, I'm not sure when is the right time to do the fragment transaction?
When the drawer starts closing? Or after it is closed?
In google's documentaion example, you can see that they are doing the transaction
right after the item click, and then close the drawer.
As a result, the drawer seems laggy and not smooth, and it looks very bad (It happens in my application too).
In Gmail and Google Drive applications, on the other way, It seems like they are doing the transaction after the drawer closed (Am I Right?).
As a result, the drawer is not laggy and very smooth, BUT it takes about 1 second (the time it takes to the drawer get closed) at least, to see the next fragment.
It seems like there is no way the drawer will be smooth when immediately doing fragment transaction.
What do you think about that?
Thanks in advance!
Yup, couldn't agree more, performing a fragment (with view) transaction results in a layout pass which causes janky animations on views being animated, citing DrawerLayout docs:
DrawerLayout.DrawerListener can be used to monitor the state and motion of drawer views. Avoid performing expensive operations such as layout during animation as it can cause stuttering; try to perform expensive operations during the STATE_IDLE state.
So please perform your fragment transactions after the drawer is closed or somebody patches the support library to somehow fix that :)
Another solution is to create a Handler and post a delayed Runnable after you close the drawer, as shown here: https://stackoverflow.com/a/18483633/769501. The benefit with this approach is that your fragments will be replaced much sooner than they would be if you waited for DrawerListener#onDrawerClosed(), but of course the arbitrary delay doesn't 100% guarantee the drawer animation will be finished in time.
That said, I use a 200ms delay and it works wonderfully.
private class DrawerItemClickListener implements OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
drawerLayout.closeDrawer(drawerList);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
switchFragments(position); // your fragment transactions go here
}
}, 200);
}
}
This is what I do to achieve an smooth transaction animation similar to Gmail app:
activity_drawer.xml
<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 -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:choiceMode="singleChoice" />
</android.support.v4.widget.DrawerLayout>
DrawerActivity.java
private Fragment mContentFragment;
private Fragment mNextContentFragment;
private boolean mChangeContentFragment = false;
private Handler mHandler = new Handler();
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
mDrawerLayout.setDrawerListener(new DrawerListener());
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
...
}
....
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
getSupportFragmentManager().beginTransaction().remove(mContentFragment).commit();
switch (position) {
case 0:
mNextContentFragment = new Fragment1();
break;
case 1:
mNextContentFragment = new Fragment2();
break;
case 2:
mNextContentFragment = new Fragment3();
break;
}
mChangeContentFragment = true;
mDrawerList.setItemChecked(position, true);
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mDrawerLayout.closeDrawer(mDrawerList);
}
}, 150);
}
}
private class DrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {
#Override
public void onDrawerClosed(View view) {
if (mChangeContentFragment) {
getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).replace(R.id.content_frame, mNextContentFragment).commit();
mContentFragment = mNextContentFragment;
mNextContentFragment = null;
mChangeContentFragment = false;
}
}
}
Hope that helps you! :-)
I know this question is old but I ran into the same problem and figured I would post my solution as I think it is a better implementation than adding a hardcoded delay time. What I did was use the onDrawerClosed function to verify that the drawer IS closed before doing my task.
//on button click...
private void displayView(int position) {
switch (position) {
//if item 1 is selected, update a global variable `"int itemPosition"` to be 1
case 1:
itemPosition = 1;
//();
break;
default:
break;
}
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
mDrawerLayout.closeDrawer(mDrawerList); //close drawer
}
and then in onDrawerClosed, open the corresponding activity.
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
// calling onPrepareOptionsMenu() to show action bar icons
supportInvalidateOptionsMenu();
if (itemPosition == 1) {
Intent intent = new Intent(BaseActivity.this, SecondActivity.class);
startActivity(intent);
}
}
Just write your code in a handler and put 200 ms delay.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
openSelectionDrawerItem(position);
}
}, 200);
Instead of delaying your item clicks which may make your app feel slow. I would just delay the closing of the mDrawerLayout. I would not use the DrawerLayout.OnDrawerListener onClose(...) either because those callbacks are so slow to be called.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mDrawerLayout.closeDrawer(GravityCompat.START);
}
}, 200);
If you want it smooth and without any delay, leave the drawer open and close it afterwards when returning (in the onRestart() method).
#Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
mDrawerLayout.closeDrawer(mDrawerList);
}
The side effect is an (speedy) animation when returning, but this might be acceptable.
Several tries to ask this question in #android-dev (irc) and hours of searching, but I still don't have a solution to this problem.
I'm currently working on the search-function in my android music player. I'm using the amazing ActionBarSherlock to provide support for older android versions.
My Problem is the following:
When the user clicks the search menu/action button, the actionView of the clicked action should be expanded, and a new Fragment (the searchFragment) should be shown instead of the currently active one.
However when i'm attempting to do this, the actionView doesn't expand.
I've tried to expand the actionView, without adding the SearchFragment, and in that case the actionView DOES expand. However the combination seems impossible.
Here's my code:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null) {
if (item.getItemId() == R.id.collectionactivity_search_menu_button) {
item.expandActionView();
mTabsAdapter.replace(new SearchFragment(), false);
return true;
}
}
return false;
}
/**
* Replaces the view pager fragment at specified position.
*/
public void replace(int position, Fragment newFragment, boolean isBackAction) {
// Get currently active fragment.
ArrayList<Fragment> fragmentsStack = mFragments.get(position);
Fragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
if (currentFragment == null) {
return;
}
// Replace the fragment using a transaction.
this.startUpdate(mViewPager);
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.attach(newFragment).remove(currentFragment).commit();
if (isBackAction == true)
fragmentsStack.remove(currentFragment);
else
fragmentsStack.add(newFragment);
this.notifyDataSetChanged();
this.finishUpdate(mViewPager);
}
The mTabsAdapter.replace(...) method replaces the currently shown Fragment with the one in the first parameter. In Addition the fragment is being added to a custom backStack.
Replacing the Fragment before or after expanding the View didn't make any difference.
Hopefully somebody is able to help me :)
thanks in advance!
Have you tried setting your actionviews android:showAsAction to collapseActionView? that way you don't have to manage the expand/close action.
If that does not work you can handle it in another way,you set an expand listener and replace your fragment once your action view starts expanding
item.setOnActionExpandListener(new OnActionExpandListener() {
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Do something when collapsed
return true; // Return true to collapse action view
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
mTabsAdapter.replace(new SearchFragment(), false);
return true; // Return true to expand action view
}
});
remember to return true to let the actionview expand
I found out what the problem was caused by.
My mTabsAdapter.replace(..) method was calling notifyDataSetChanged();. So everytime I replaced the fragment, onPrepareOptionsMenu was being called, resulting in the search action button being removed and added again, thus resulting in the actionView being collapsed.
The solution to this is to fix my onPrepareOptionsMenu, so the actionView will be expanded again, whenever onPrepareOptionsMenu is called and the actionView was expanded before.