I've search anywhere but I haven't found it. Anything I've found this far is always hiding the Action Bar when a ListView, GridView or RecyclerView is scrolled. What I need is how to hide the Action Bar when a ViewGroup (using ScrollView for example) is scrolled? Because I can't really convert my layout to any of those three, and there is no onScrollListener for ScrollView.
Thank you.
1.implement ViewTreeObserver.OnScrollChangedListener into your class,
2.Write this line into your onCreate "getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);" (without quotes)
3.Now get ActionBar Height for Hide animation as follows -
final TypedArray mstyled = getTheme().obtainStyledAttributes(new int[]{android.R.attr.actionBarSize });
mActionBarHeight = styledAttributes.getDimension(0, 0);
mstyled.recycle();
4.Get Action Bar.
mActionBar = getActionBar();
5.Intilize scrollview.
((ScrollView)findViewById(R.id.parent)).getViewTreeObserver().addOnScrollChangedListener(this);
6.override onScrollChange and mode your method like this.
#Override
public void onScrollChanged() {
float mfloat = ((ScrollView)findViewById(R.id.parent)).getScrollY();
if (mfloat >= mActionBarHeight && mActionBar.isShowing()) {
mActionBar.hide();
} else if ( mfloat==0 && !mActionBar.isShowing()) {
mActionBar.show();
}
}
Hope it Helps.
Using
android.support.v4.widget.NestedScrollView
instead
Scrollview.
It worked good
Related
I'm trying to make a set of views (that include several textviews and buttons - all in different parent layouts, but in the same activity) invisible if a particular condition is evaluated to false.
The conventional way to do that would be:
findViewById(R.id.myview).setVisibility(View.INVISIBLE);
My question is, will I have to do this for all the views one by one that I want to be invisible, And then toggle them back when I want them visible?
Or, is there a way to avoid the code-repetition?
If the Views are in different parents , you can't do it directly, but you can implement a method to change the visibility of a bunch of Views if you want to keep your code clean:
List<View> relatedViews = new ArrayList<>();
// ...
relatedViews.add(view1);
relatedViews.add(view2);
relatedViews.add(view3);
// ...
changeVisibility(relatedViews, View.INVISIBLE);
// ...
private void changeVisibility(List<View> views, int visibility) {
for (View view : views) {
view.setVisibility(visibility);
}
}
As a side note, you may want to change the visibility to View.GONE instead of View.INVISIBLE so it doesn't take any space in the layout.
you can use something like this. It's not the most elegant solution but works.
The idea is give to each view that you want to hide a same content description, because in the same layout you can not use same id for multiple view. With the same content description you can find all views in your layout and hide them.
That's an example considering the first layout as Linear. You can change obviously ;)
public class TestActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
LinearLayout rootLayout = (LinearLayout)findViewById(R.id.rootLayout);
int childcount = rootLayout.getChildCount();
for (int i=0; i < childcount; i++){
View v = rootLayout.getChildAt(i);
if(v.getContentDescription() != null && v.getContentDescription().equals("invisibleView")){
v.setVisibility(View.INVISIBLE);
//I suggest you to use GONE instead of INVISIBLE to remove the space of the view
}
}
}
}
in your xml give to the object that you want to hide this property
android:contentDescription="invisibleView"
Use varargs method for show or hide multiple views.
for example if you have views like view1, view2.....etc
then just call setVisibility(View.VISIBLE,view1,view2)
public static void setVisibility(int visibility, View... views){
for (View view : views){
view.setVisibility(visibility);
}
}
I am using Activity class with (usually) one fragment as a content. In the Activity I use CollapsingToolbarLayout as some kind of header for some information and everything works fine. But in some cases (when some fragments are attached) I don't want to show that info, I don't want CollapsingToolbarLayout to open on scroll.
What I want to achieve is to lock CollapsingToolbarLayout, prevent it from opening from the fragment. I am collapsing it programmatically with appBarLayout.setExpanded(false, true);
I came up with a different method as setting the nested scrolling flag only works when dragging the NestedScrollView. The appbar can still be expanded by swiping on the bar itself.
I set this up as a static function in "Utils" class. Obviously the flags you set upon unlocking will depend on which ones are relevant for your use case.
This function assumes you are are starting with an expanded toolbar
public static void LockToolbar(boolean locked, final AppBarLayout appbar, final CollapsingToolbarLayout toolbar) {
if (locked) {
// We want to lock so add the listener and collapse the toolbar
appbar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (toolbar.getHeight() + verticalOffset < 2 * ViewCompat.getMinimumHeight(toolbar)) {
// Now fully expanded again so remove the listener
appbar.removeOnOffsetChangedListener(this);
} else {
// Fully collapsed so set the flags to lock the toolbar
AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
lp.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED);
}
}
});
appbar.setExpanded(false, true);
} else {
// Unlock by restoring the flags and then expand
AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
lp.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
appbar.setExpanded(true, true);
}
}
Well, I managed to solve it myself. The trick is to disable nested scrolling behaviour with ViewCompat.setNestedScrollingEnabled(recyclerView, expanded);
As I am using one fragment in the activity as a content view and putting it on the backstack I simply check when backstack has changed and which fragment is visibile. Note that I NestedScrollView in every fragment to trigger collapsible toolbar. This is my code:
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
NestedScrollView nestedScrollView = (NestedScrollView)findViewById(R.id.nested_scroll_view);
int size = getSupportFragmentManager().getBackStackEntryCount();
if (size >= 1 && nestedScrollView != null) {
if (getSupportFragmentManager().getBackStackEntryAt(size - 1).getName().equals("SpotDetailsFragment")) {
Log.d(LOG_TAG, "Enabling collapsible toolbar.");
ViewCompat.setNestedScrollingEnabled(nestedScrollView, true);
} else {
Log.d(LOG_TAG, "Disabling collapsible toolbar.");
ViewCompat.setNestedScrollingEnabled(nestedScrollView, false);
}
}
}
});
This thread helped me a lot, where another possible solution is presented:
Need to disable expand on CollapsingToolbarLayout for certain fragments
In my activity I do:
setSupportActionBar(toolbar);
where toolbar is an instance of android.support.v7.widget.Toolbar
Is there any way after this to hide and show back Toolbar widget programmatically? I already tried
toolbar.setVisibility(View.INVISIBLE);
but this only makes it invisible and it still takes space, so that content of the activity starts after it, and I see white space instead in the header.
INVISIBLE only hides the view.
GONE however, will hide the view and prevent it from taking up any space.
toolbar.setVisibility(View.GONE);
If your toolbar is inside the AppBarLayout then you can use setExpanded method of AppBarLayout to expand and collapse the toolbar with or without animation.
setExpanded(boolean expanded, boolean animate)
this method is available from v23 of Support Library.
From the documentation for reference.
As with AppBarLayout scrolling, this method relies on this layout being a direct child of a CoordinatorLayout.
expanded : true if the layout should be fully expanded, false if it should be fully collapsed
animate : Whether to animate to the new state
AppBarLayout appBarLayout = (AppBarLayout)findViewById(R.id.appBar);
to expand the toolbar with animation.
appBarLayout.setExpanded(true, true);
to collapse the toolbar with animation.
appBarLayout.setExpanded(false, true);
Here is my code try this. It worked perfectly for me.
private static final float APPBAR_ELEVATION = 14f;
private void hideAppBar(final AppBarLayout appBar) {
appBar.animate().translationY(-appBar.getHeight()).setInterpolator(new LinearInterpolator()).setDuration(500);
}
public void showAppBar(final AppBarLayout appBar){
appBar.animate().translationY(0).setInterpolator(new LinearInterpolator()).setDuration(500).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
appBar.setElevation(APPBAR_ELEVATION);
}
});
}
Hope this might help you
I have been looking for answers on how to place the indeterminate horizontal progress bar below the action bar using AppCompat. I'm able to get the horizontal progress bar to appear, but it is at the top of the action bar. I want it under/below the action bar kind of like how gmail does it (except without the pull to refresh).
I used the following code to have the progress bar appear:
supportRequestWindowFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.main_activity);
setSupportProgressBarIndeterminate(Boolean.TRUE);
setSupportProgressBarVisibility(true);
but this places the horizontal progress bar at the top of the action bar. Anyone know how to place the progress bar below the action bar?
I faced a similar problem recently and solved it by creating my own progressbar and then aligning it by manipulating getTop() of the content view.
So first create your progressbar.
final LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 20); //Use dp resources
mLoadingProgressBar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
mLoadingProgressBar.setIndeterminate(true);
mLoadingProgressBar.setLayoutParams(lp);
Add it to the window (decor view)
final ViewGroup decor = (ViewGroup) getWindow().getDecorView();
decor.addView(mLoadingProgressBar);
And in order to get it to its correct position Im using a ViewTreeObserver that listens until the view has been laid out (aka the View.getTop() isnt 0).
final ViewTreeObserver vto = decor.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
final View content = getView(android.R.id.content);
#Override
public void onGlobalLayout() {
int top = content.getTop();
//Dont do anything until getTop has a value above 0.
if (top == 0)
return;
//I use ActionBar Overlay in some Activities,
//in those cases it's size has to be accounted for
//Otherwise the progressbar will show up at the top of it
//rather than under.
if (getSherlock().hasFeature((int) Window.FEATURE_ACTION_BAR_OVERLAY)) {
top += getSupportActionBar().getHeight();
}
//Remove the listener, we dont need it anymore.
Utils.removeOnGlobalLayoutListener(decor, this);
//View.setY() if you're using API 11+,
//I use NineOldAndroids to support older
ViewHelper.setY(mLoadingProgressBar, top);
}
});
Hope that makes sense for you. Good luck!
I'm using a custom view for the ActionBar with Tabs. My problem is the ordering of the custom view. Android is displaying it AFTER the tabs - which I do not want.
I want the custom view displayed BEFORE the tabs.
Is there a way to customize the actionBar to show the custom view before the tabs? or is this not possible?
Code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
View customActionBarView =
getLayoutInflater().inflate(R.layout.home_actionbar, null, true);
ActionBar.LayoutParams lp =
new ActionBar.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.START;
bar.setCustomView(customActionBarView, lp);
bar.setLogo(R.drawable.logo);
bar.setHomeButtonEnabled(true);
bar.setDisplayShowCustomEnabled(true);
bar.addTab(bar.newTab()
.setText("Stuff")
.setTabListener(new TabListener<StuffFragment>(
this, "stuff", StuffFragment.class)));
bar.addTab(bar.newTab()
.setText("Friends")
.setTabListener(new TabListener<ContactsFragment>(
this, "friends", ContactsFragment.class)));
bar.addTab(bar.newTab()
.setText("Messages")
.setTabListener(new TabListener<ConversationsFragment>(
this, "messages", ConversationsFragment.class)));
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM |
ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO);
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}
This seems to be the intended behaviour when using tabs and custom views.
https://code.google.com/p/android/issues/detail?id=36191#c3
If you take a look at ActionBarSherlock - Tabs appearing ABOVE actionbar with custom view many other people are experiencing this as well and some people have offered solutions.
I have been unable to get any of the solutions working, but they may work for you. The trick seems to be to make sure the logo is is not set to be hidden. Call
getActionBar().setDisplayShowHomeEnabled(true) or getSupportActionBar().setDisplayShowHomeEnabled(true) if using ActionBarSherlock.
Then call:
View homeIcon = findViewById(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
android.R.id.home : R.id.abs__home);
((View) homeIcon.getParent()).setVisibility(View.GONE);
((View) homeIcon).setVisibility(View.GONE);
This will get a reference to the actionbar view that holds the logo and sets it to gone with enables the custom view to fill the entire parent view, but should keep the tabs underneath...
As I said I was unable to get this working, but some people have had success.
Good luck.
I had the same problem and i figured out a way to solve it.
It's not an "elegant" solution but it was the best i could find.
As first thing since you want to modify the standard ActionBar behaviour you have to force ActionBar Sherlok to always use the non native implementation.
To do that open ActionBarSherlok.java and comment this line of code:
registerImplementation(ActionBarSherlockNative.class);
then remove all the values-v11 values-v14 etc and be sure to always extend Theme.Sherlock and never Theme.Holo
At this point you are sure that the ActionBar implementation is always the one written by Jake Wharton.
The only thing left to do is make the ActionBar view layout the way you want.
Open ActionBarView.java and in the onLayout() method move this piece of code
if (mExpandedActionView == null) {
final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
(mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
if (showTitle) {
x += positionChild(mTitleLayout, x, y, contentHeight);
}
switch (mNavigationMode) {
case ActionBar.NAVIGATION_MODE_STANDARD:
break;
case ActionBar.NAVIGATION_MODE_LIST:
if (mListNavLayout != null) {
if (showTitle) x += mItemPadding;
x += positionChild(mListNavLayout, x, y, contentHeight) + mItemPadding;
}
break;
case ActionBar.NAVIGATION_MODE_TABS:
if (mTabScrollView != null) {
if (showTitle) x += mItemPadding;
x += positionChild(mTabScrollView, x, y, contentHeight) + mItemPadding;
}
break;
}
}
right before this piece
if (mProgressView != null) {
mProgressView.bringToFront();
final int halfProgressHeight = mProgressView.getMeasuredHeight() / 2;
mProgressView.layout(mProgressBarPadding, -halfProgressHeight,
mProgressBarPadding + mProgressView.getMeasuredWidth(), halfProgressHeight);
}
You're done!
Hope this helps
When you add your custom view to the ActionBar you can specify the gravity also.
ActionBar.LayoutParams lp = new ActionBar.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.LEFT;
customView.setLayoutParams(lp);
use ActionBarSherlock, which is very good implementation of Custom ActionBar for all android versions and very easy to use.
or you can create your own ActionBar using custom title bar and and its fair enough easy to implement. You can see this and this examples are very good examples of custom title bars.
Are you making an app for the tablet? As far as I know, the tabs bar of actionbar basically appears below the it on cellphone.
If on tablet, I'm afraid you can't adjust the positions of tabs. what I can think of is that you need to quit using navigation mode and make a custom view which look like tabs to replace the actionBar tabs. Of course this causes a lot of extra effort to deal with the navigation stuff.
Just create a custom view for your home button. In this view you can combine both logo and the custom view you're trying to position on left. Then add tabs as normal
The only downside of this solution is that you'll need to maintain the state of the back button yourself (if you use it at all)
First set "DisplayShowHomeEnabled" property of actionbar to "true":
actionBar.setDisplayShowHomeEnabled(true);
and then:
View homeIcon = findViewById(android.R.id.home);
((View) homeIcon.getParent()).setVisibility(View.GONE);
((View) homeIcon).setVisibility(View.GONE);
I hope it helps :)