I have Toolbar and ScrollView in my layout. I wanna Hide/Show Toolbar when user scroll ScrollView. There was the same questions before here in stackoverflow but I didnt find right answer. Here below code which I used. Unfortunatly it works only with ActionBar. Is it any was to use this with Toolbar cause now I have errors in isShowing, hide, show methods?
Thanks for any help!
public class MainActivity extends ActionBarActivity implements ViewTreeObserver.OnScrollChangedListener{
private float mToolbarBarHeight;
Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
mToolbar = (Toolbar) findViewById(R.id.application_toolbar);
setSupportActionBar(mToolbar);
//hiding the toolbar
final TypedArray mTypedArray = getTheme().obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
mToolbarBarHeight = mTypedArray.getDimension(0, 0);
mTypedArray.recycle();
((ScrollView)findViewById(R.id.mScrollView)).getViewTreeObserver().addOnScrollChangedListener(this);
}
****
#Override
public void onScrollChanged() {
float y = ((ScrollView)findViewById(R.id.mScrollView)).getScrollY();
if (y >= mToolbarBarHeight && mToolbar.isShowing()) {
mToolbar.hide();
} else if ( y==0 && !mToolbar.isShowing()) {
mToolbar.show();
}
}
}
Related
This is a variant on a familiar problem (such as this: Setting action bar title in ViewPager)
I have a ViewPager setup in my main activity. The ViewPager is set to represent a date. I've set it up with an OnPageChangeListener and onPageListener to set the toolbar title to a given date (the default on startup being the current date). onPageListener is called, but some other event is called afterwards, and it sets the toolbar title back to the defined app name. Even setting it explicitly in the activity's onCreate doesn't fix the title, it is still replaced by the app name.
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private Date _displayedDate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setAdapter(new DatePagerAdapter(getSupportFragmentManager()));
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
_displayedDate = DateUtils.offsetDate(position);
showDisplayedDate(); // no apparent effect
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
_displayedDate = new Date();
viewPager.setCurrentItem((int)DateUtils.getDayOffset(_displayedDate));
showDisplayedDate(); // no apparent effect
}
public void showDisplayedDate() {
if (_displayedDate != null) {
toolbar.setTitle(_displayedDate.toString())); // simplified version of date display
}
}
}
public class DatePagerAdapter extends FragmentStatePagerAdapter
So, what gives? How do I set the title based on the ViewPager's initial display?
As stated here, this removes the automatic app title in the toolbar, and the rest of the logic takes care of displaying the date:
getSupportActionBar().setDisplayShowTitleEnabled(false);
I am trying to create a collapsible toolbar like the one on chesesquare repository, but I am facing this problem:
https://www.youtube.com/watch?v=THdxcyEc1CA&feature=youtu.be
Anyone know how to solve this problem?
You can check the state of AppBarLayout on configuration change(orientation), store it. Then you can set that state for the AppBarLayout after configuration change applied.
public class CheeseDetailActivity extends AppCompatActivity {
public static final String EXTRA_NAME = "cheese_name";
AppBarLayout appBarLayout;
boolean isCollapsed = false;
//state change listener
AppBarLayout.OnOffsetChangedListener toolbarStateListener = new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (verticalOffset == 0) {
// Collapsed
isCollapsed = true;
} else {
// Not collapsed
isCollapsed = false;
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Intent intent = getIntent();
final String cheeseName = intent.getStringExtra(EXTRA_NAME);
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
CollapsingToolbarLayout collapsingToolbar =
(CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle(cheeseName);
//getting app bar layout
appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
//set listener to listen state change of app bar layout
appBarLayout.addOnOffsetChangedListener(toolbarStateListener);
loadBackdrop();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
//save state on orientation change
savedInstanceState.putBoolean("isCollapsed", isCollapsed);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//get state on orientation change
isCollapsed = savedInstanceState.getBoolean("isCollapsed");
}
#Override
protected void onResume() {
super.onResume();
//set state of app bar layout
appBarLayout.setExpanded(isCollapsed);
}
private void loadBackdrop() {
final ImageView imageView = (ImageView) findViewById(R.id.backdrop);
Glide.with(this).load(Cheeses.getRandomCheeseDrawable()).centerCrop().into(imageView);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.sample_actions, menu);
return true;
}
}
I have edited CheeseDetailActivity in CheeseSquare repository.
On the onConfigurationChanged you could try to run
handler.postDelayed(new Runnable(){
#Overrride
public void run(){
toolbar.invalidate();
}
},[Try different time lapses(miliseconds)]);
my application provide different contents, some of them is with image and others not.
For those which have image i am using CollapsingToolbarLayout it works fine but for those which have not image I want collapse CollapsingToolbarLayout and prevent expanding, disable it.
Here is my item activity code:
public class ItemActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item);
collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setStatusBarScrimResource(R.color.black_transparent_190);
collapsingToolbar.setContentScrimResource(R.color.gray_transparent_150);
collapsingToolbar.setExpandedTitleTextAppearance(R.style.MyTheme_Toolbar_Title_Expanded);
appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
appBarLayout.setExpanded(false);
loadData();
}
public void loadData() {
if(haveImage) {
// loading data and image
appBarLayout.setExpanded(true, true);
} else {
appBarLayout.setExpanded(false);
}
}
}
I have already tried
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbar.getLayoutParams();
params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
collapsingToolbar.setLayoutParams(params);
and
CollapsingToolbarLayout.LayoutParams mParams = new CollapsingToolbarLayout.LayoutParams(collapsingToolbar.getLayoutParams());
mParams.setCollapseMode(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_OFF);
mToolbar.setLayoutParams(mParams);
It works, it's prevent collapsing!
But collapsing toolbar is expanded!
How can I collapse toolbar and disable it for scrolling events?
You use setExpanded(false) on appBarLayout as normal, but you need to create a custom CollapsingToolbarLayout as below
I followed the idea in this link.
Override CollapsingToolbarLayout and override dispatchTouchEvent returning true like this
public class MyCustomCollapsingToolbarLayout extends CollapsingToolbarLayout {
public MyCustomCollapsingToolbarLayout(Context context) {
super(context);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return true;
}
}
My app has a toolbar that should be present on every view. Currently, I do the following in my onCreate() method for each Activity I have:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Does this need to be done in every onCreate() method in every Activity or is there a simpler way? Also, as a side question, how can I implement a "back" feature in the toolbar that takes the user back one action if they click it?
Create a Base class for Activity
public abstract class BaseActivity extends AppCompatActivity {
Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResource());
configureToolbar();
}
protected abstract int getLayoutResource();
private void configureToolbar() {
toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
FragmentManager fm = getSupportFragmentManager();
if (fm != null && fm.getBackStackEntryCount() > 0) {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
} else {
finish();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
And in each Activity extends this BaseActivity to get the ToolBar and implementing the back feature.
At last don't forget to include the ToolBar in each activity layout.
Edit:
Override that method getLayoutResource() in each Activity and pass the layout id.
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public int getLayoutResource() {
return R.layout.activity_main;
}
This is my implementation. It removes the need of the getLayoutResources() from the accepted answer and brings back the "setContentView()" in all activities as normal
public abstract class BaseActivity extends AppCompatActivity {
Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected boolean useToolbar() {
return true;
}
#Override
public void setContentView(int layoutResID) {
View view = getLayoutInflater().inflate(layoutResID, null);
configureToolbar(view);
super.setContentView(view);
}
private void configureToolbar(View view) {
toolbar = (Toolbar) view.findViewById(R.id.toolbar);
if (toolbar != null) {
if (useToolbar()) {
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} else {
toolbar.setVisibility(View.GONE);
}
}
}
}
From here on you just extend BaseActivity. If you don't want a toolbar you will have to override the useToolbar().
Don't forget to add in activity.xml at the top
<include layout="#layout/toolbar" />
toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
</merge>
It depends on your implementation but if you want avoid boilerplate code you should use good programming OO.
An Example using Fragment.
public abstract class FragmentBase extends Fragment {
protected void settingsToolbar(View rootView) {
Toolbar toolbar = (Toolbar) rootView.findViewById(R.id.toolbar);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
// TODO add your code and your requirements
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
}
I hope this can give you an idea.
If you have used Activity then Create BaseActivity that extends AppCompatActivity or ActionBarActivity(Deprecated) and move Toolbar code to BaseActivity.
public class BaseActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
}
If you have used Fragment then Create BaseFragment that extends Fragment and move Toolbar code to BaseFragment.
public class BaseFragment extends Fragment {
View main;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
main = inflater.inflate(R.layout.fragment_about, container, false);
Toolbar toolbar = (Toolbar) main.findViewById(R.id.toolbar);
getActivity().setSupportActionBar(toolbar);
return main;
}
}
In main XML layout you have to add Toolbar xml code.
Now in every view(Activity) extends BaseActivity instead of AppCompatActivity or ActionBarActivity so you can get access Toolbar in every view.
public class YourActivity extends BaseActivity{
//your code
}
EDIT1:
main.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:theme="#style/toolbarTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/green"
android:minHeight="?attr/actionBarSize" />
</RelativeLayout>
EDIT2:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
add these two lines below setSupportActionBar(toolbar); in BaseActivity.
I hope it helps!
Create a base activity and initialize your tool bar in this class. Now it can be extends to all other child activity.
FirtActivity extends BaseActivity
SecondActivity extends BaseActivity
In base activity toll bar back button click you can check like below mentioned way
if(this instance of FirstActivity){
//do stuff here
}else if(this instance of SecondActivity){
//do stuff here
}
Ok, so hiding the action bar is something doable. But, how can we hide the (newly introduced) toolbar in our activity?
I am making an app with an activity having theme as theme.apcompat.light.noactionbar(to hide the action bar) , I have placed a toolbar with slidingtablayout below it. And below it is my listview.
What I want is to hide the toolbar when I scroll the listview up. But the slidingtablayout should remain there. And while in middle of the listview if I scroll down, the toolbar should again be visible.
Updated (8/24/2015):
Please see my latest answer here using the Design Support Library:
Hiding the ActionBar on RecyclerView/ListView onScroll
Updated (6/2/2015):
ListView + ToolBar - without Libraries:
Please see https://stackoverflow.com/a/26547550/950427 and https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/BaseActivity.java.
mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.fragment_drawer);
mNavigationDrawerFragment.setup(R.id.fragment_drawer, (DrawerLayout) findViewById(R.id.drawer), mToolbar);
mToolbar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
mToolbar.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
mToolbar.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
mToolbar.animate().translationY(-mToolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).start();
}
});
From: http://pastebin.com/yeMX3VYP
ListView + ActionBar - without Libraries:
https://stackoverflow.com/a/17767691/950427
I recently wanted the same functionality and this works perfectly for me:
As the user scrolls upward, the ActionBar will be hidden in order to give the user the entire screen to work work with.
As the user scrolls downward and lets go, the ActionBar will return.
getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
listView.setOnScrollListener(new OnScrollListener() {
int mLastFirstVisibleItem = 0;
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) { }
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (view.getId() == listView.getId()) {
final int currentFirstVisibleItem = listView.getFirstVisiblePosition();
if (currentFirstVisibleItem > mLastFirstVisibleItem) {
// getSherlockActivity().getSupportActionBar().hide();
getSupportActionBar().hide();
} else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
// getSherlockActivity().getSupportActionBar().show();
getSupportActionBar().show();
}
mLastFirstVisibleItem = currentFirstVisibleItem;
}
}
});
Use the following code:
ViewCompat.setNestedScrollingEnabled(listView, true);
for recyclerView i managed it to make it like this:
public class FragmentsOnScrollListener extends RecyclerView.OnScrollListener {
private final MainActivity mainActivity;
private final View bothToolbarLayouts;
private int approxToolbarHeight;
public FragmentsOnScrollListener(MainActivity activity) {
mainActivity = activity;
bothToolbarLayouts = mainActivity.getBothToolbarLayouts();
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
approxToolbarHeight += dy;
bothToolbarLayouts.animate().translationY(-approxToolbarHeight).setInterpolator(new AccelerateInterpolator()).start();
}
}