I am having an issue with the toolbar and the back button. Here is the setup I have:
When I add a detail fragment, I animate the toolbar hamburger as outlined here. and this causes the hamburger to animate to an arrow.
Even in the comments section, a user mentions:
This works perfectly. Just set start=0 and end=1 to go from hamburger
to arrow, and start=1 and end=0 for arrow to hamburger. One thing
you'll have to keep track of is when the drawer is closed when the
arrow is shown. At this point, the hamburger ends up being shown
(because of the drawer's slide), which you'll have to correct.
But I cannot figure out how to get the back arrow to function properly. When I press the back arrow, the drawer opens and the detail fragment does not pop. How should I go about implementing this?
Questions
How should I animate hamburger to back arrow when adding a detail fragment? assuming the linked solution is not good enough.
How do I override the back arrow to perform only specific functions I wish? like animate to hamburger, pop back stack and NOT open the drawer.
After several hours of searching and playing around, I was able to build a solution that delivered on each requirement. Sources: 1,2
detailFragmentActive = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
setSupportActionBar(mToolbar);
...
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(detailFragmentActive) {
onBackPressed();
//if(displayBackAgain)
//return; //return after so you don't call syncState();
}else if (mDrawerLayou.isDrawerOpen(GravityCompat.START))
mDrawerLayout.closeDrawer(GravityCompat.START);
else
mDrawerLayout.openDrawer(GravityCompat.START);
mDrawerToggle.syncState();
}
});
}
private void animateHamburger(boolean isArrow){
int start = 0, end = 1;
if(isArrow){
detailFragmentActive = false;
start = 1; end = 0;
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}else{
detailFragmentActive = true;
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
ValueAnimator anim = ValueAnimator.ofFloat(start, end);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float slideOffset = (Float) valueAnimator.getAnimatedValue();
mDrawerToggle.onDrawerSlide(mDrawerLayout, slideOffset);
}
});
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(500);
anim.start();
}
#Override
public void onBackPressed() {
super.onBackPressed();
animateHamburger(true);
}
public void onFragmentChange(){
...
animateHamburger(false);
}
You can set listener for this button:
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (flagDeterminingAction) {
drawerLayout.openDrawer(drawerListView);
} else {
onBackPressed();
//or popbackstack or whatever you are using to going back in navigation
}
}
Related
I want to change tool bar back arrow to a cross icon with animation. I found some one has already make the necessary vector drawable files in this git page. So I applied it to the back arrow but it only working correctly for the first time. after that it is like setting the last result of the animation and running the animation. refer below gif
This is my code.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
AnimatedVectorDrawableCompat animDrawable;
if(firstRun){
if (!moreDetailFragmentIsHidden) {
animDrawable = AnimatedVectorDrawableCompat.create(this,
R.drawable.vector_back_arrow_to_cross);
animDrawable.start();
getSupportActionBar().setHomeAsUpIndicator(animDrawable);
}else{
animDrawable = AnimatedVectorDrawableCompat.create(this,
R.drawable.vector_cross_to_back_arrow);
animDrawable.start();
getSupportActionBar().setHomeAsUpIndicator(animDrawable);
}
}else{
firstRun = true;
}
return super.onCreateOptionsMenu(menu);
}
on bottom blue bar click i'm calling invalidateOptionsMenu()
private void onClickBottomMessageContainer() {
bottomMessageContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (moreDetailFragmentIsHidden) {
moreDetailFragmentHolder.startAnimation(revealFromBottom);
moreDetailFragmentHolder.setVisibility(View.VISIBLE);
moreDetailFragmentIsHidden = false;
invalidateOptionsMenu();
} else {
moreDetailFragmentHolder.startAnimation(unRevealFromBottom);
moreDetailFragmentHolder.setVisibility(View.GONE);
moreDetailFragmentIsHidden = true;
invalidateOptionsMenu();
}
}
});
}
The DrawerLayout take noticeable time to close
here is my code:
#Override
public void onDrawerOpened(View drawerView) {
if (items.size() == 0)
view.setVisibility(View.GONE);
else view.setVisibility(View.VISIBLE);}
super.onDrawerOpened(drawerView);
invalidateOptionsMenu();
}
is there a solution for that?
Your problem is that the onDrawerOpened() method doesn't fire until the drawer is completely open. The perceived delay is due to the View being visible during the opening.
One solution would be to disable dragging the drawer, and only allow the toggle to open and close it. You could then do your size check before opening it programmatically. This, though, would require locking the drawer to the appropriate state in each of the onDrawerOpened() and onDrawerClosed() methods, and, of course, you'd lose that standard mode of interaction.
The preferred option is probably to do the check and visibility setting as soon as possible as the drawer is starting to open. We can do this in the onDrawerSlide() method instead, keeping a boolean flag to determine if the drawer is sliding after having been closed. For example:
actionBarDrawerToggle = new ActionBarDrawerToggle(...) {
private boolean opened;
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
if (slideOffset == 0) {
opened = false;
}
else {
if (!opened) {
opened = true;
if (items.size() == 0) {
view.setVisibility(View.GONE);
}
else {
view.setVisibility(View.VISIBLE);
}
}
}
}
...
}
have you include
actionBarDrawerToggle.syncState()
What does syncState() exactly do?
Well, ActionBarDrawerToggle.syncState() will synchronize the changed icon's state, which deponds on actions of DrawerLayout. If you ever tried to remove the syncState(), you will realize that the icon of arrow won't rotate any more.
I have a menu button on the bottom and I have display menu icons from another activity like MenuTask.
But how to close that MenuTask activity if the user clicks again in the menu?
imgMenu.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
if (key == 0) {
// I want to show menu here
key = 1;
Intent intent = new Intent(MainActivity.this, MenuAction.class);
startActivityForResult(intent, 2);
setResult(0);
} else if (key == 1) {
// I want to Delete menu here
key = 0;
//onBackPressed();
finish();
}
}
});
Note: I think if i click second time , button could not fire. it means else part not execute.
Problem:
I have Clicked, right top menu button and open new activity menu action. but if i want to click again same menu button, i want to disappers that menu action. but menu button could not clicked.
How to make MenuButton Clickable? any idea? any other menthod? But when i click mobile backbutton menuaction layout disappeared.
Thanks in advance.
I thing this is not best way. You must use Fragment
If you want only kill activity MenuAction.this.finish();
#Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
// handler to delay
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
you can go though this link Clicking the back button twice to exit an activity
same question
Since this topic is quite popular, I have to say that I searched tons of similar questions and still don't have a working solution.
Problem short description: in my Activity I have a "search mode", when it starts I show the soft keyboard, when it finishes, I want to hide the keyboard, but can't find a way to do it.
What I have tried:
using flag InputMethodManager.HIDE_IMPLICIT_ONLY instead of 0
using flag InputMethodManager.HIDE_NOT_ALWAYS instead of 0
setting windowSoftInputMode="stateAlwaysHidden"
setting windowSoftInputMode="stateHidden"
Nothing seems to work, the keyboard stays visible. The code starting the "search mode":
private void onStartSearch(){
isSearch = true;
tvMyFriends.setVisibility(View.GONE);
etSearch.setVisibility(View.VISIBLE);
etSearch.startAnimation(AnimationUtils.loadAnimation(this, R.anim.on_show_search));
etSearch.requestFocus();
invalidateOptionsMenu();
imm.showSoftInput(etSearch, InputMethodManager.SHOW_IMPLICIT);
}
The code that finishes the "search mode":
private void onCancelSearch(){
Animation animHideSearch = AnimationUtils.loadAnimation(this, R.anim.on_cancel_search);
animHideSearch.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
/* no action required */
}
#Override
public void onAnimationEnd(Animation animation) {
etSearch.setVisibility(View.GONE);
tvMyFriends.setVisibility(View.VISIBLE);
isSearch = false;
invalidateOptionsMenu();
if(etSearch.getText().toString().length()>0)
etSearch.setText("");
etSearch.clearFocus();
imm.hideSoftInputFromInputMethod(etSearch.getWindowToken(), 0);
}
#Override
public void onAnimationRepeat(Animation animation) {
/* no action required */
}
});
etSearch.startAnimation(animHideSearch);
}
The question: how can I force the damn keyboard to disappear?
UPD: set a bounty. Still looking for a reliable, device-independent solution to force-hide the soft keyboard OR to detect whether the keyboard is currently showing.
Hide the keyboard before changing the Visibility of you EditText to GONE.
...
imm.hideSoftInputFromWindow(etSearch.getWindowToken(), 0);
etSearch.setVisibility(View.GONE);
...
Just want to perform slide animation on back press..Here is my code:
txtBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
overridePendingTransition(R.anim.left_out, R.anim.right_in);
onBackPressed();
}
});
I don't want to use intent for a reason.
Try:
finish();
overridePendingTransition(R.anim.left_out, R.anim.right_in);
overridePendingTransition() must be called after finish().