ImageView in action bar - android

I am trying to put an ImageView inside the action bar, it works, and I can animate it and everything, however, it takes too much horizontal space and I don't know why.
This is my menu:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<ImageView
android:id="#+id/dicebutton"
android:layout_width="wrap_content"
android:layout_height="?attr/actionBarSize"
android:contentDescription="dice"
android:src="#drawable/dice_1" />
</android.support.v7.widget.Toolbar>
And this is the code in the Activity:
if (myToolbar != null) {
setSupportActionBar(myToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setElevation(0);
image = myToolbar.findViewById(R.id.dicebutton);
if (image != null) {
image.setImageResource(R.drawable.dice_1);
image.setScaleX(0.5f);
image.setScaleY(0.5f);
image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rollDice(Helper.rand.nextInt(6) + 1, v);
}
});
}
}
Here is an image of the result:
The image I am using is a 256x256 dice image, why is it enlarging it to take all this space?

I too had so many problems with drawing and adjusting views in actionbar before. I think you should try Support Library Toolbar , it gives you a lot more control with this cases , also supports Menu inflate things as far as i recall:
https://developer.android.com/training/appbar/setting-up
https://developer.android.com/reference/android/support/v7/widget/Toolbar
You can put images and other views inside this , with much more control.
Updated Answer:
I'm not sure if this is what you need but try adding android:adjustViewBounds="true" to your image.
Turns sth like this:
To sth like this:

Related

Animating views in AppBarLayout

I have an AppBarLayout inside a coordinatorLayout as follows:
<coordinatorLayout>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TabLayout
android:id="#+id/scrollable_category_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways|snap"
app:tabGravity="center"
app:tabMode="scrollable" />
<RelativeLayout
android:id="#+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="100dp"
android:background="#android:color/white"
android:visibility="visible">
<few more layout/>
</RelativeLayout>
</android.support.design.widget.AppBarLayout>
<more views>
</coordinatorLayout>
I want the relativeLayout to be hidden by default and if the API gives a particular response then I will show the RelativeLayout with its content. The content can have varying height depending on the API response (eg. Text can be single line or multiline etc.). So I dont know the height of the view in the begining. Now I want to apply a translationY to the view such that it appears to be coming from beneath the tabLayout (showing shadows etc.).
I have tried many solutions, one of which is:
adParentLayout.animate()
.translationY(0)
.setDuration(5000)
.withEndAction(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "Animation Complete", Toast.LENGTH_SHORT).show();
}
})
.withStartAction(new Runnable() {
#Override
public void run() {
adParentLayout.setVisibility(View.VISIBLE);
adParentLayout.setTranslationY(-adParentLayout.getHeight());
}
});
This obviously doesn't work. I dont know much about animations and would like suggestions.
One solution I tried was making the view visible in the layout and then apply translation. But this makes the view translate above the TabLayout covering it completely. It turns out that AppBarLayout extends LinearLayout, so the second Layout RelativeLayout translated above it. I dont understand how this effect can be achieved and any input in the right direction will be helpful.
I got it working with LayoutTransition. Basically I just added android:animateLayoutchanges=true in appBarLayout and it handled animating the visibility of the view.
I didnt know about this. Seems like a great thing to have.

How to make hide/show toolbar when our list scrolling to the top

How to make hide/show toolbar when our list scrolling to the top, knowing that the toolbar view is described inside activity_main.xml but recyclerView is described in another fragmet nomed Fragment_main.xml
sorry for my english :)
Since your activity which has the toolbar within its content view is starting the fragment, you can always get a hold of it from your fragment.
MainActivity mainActivity = (MainActivity)getActivity();
I would recommend doing a method for it in your MainActivity:
public void showToolbar(boolean show) {
// If you have your toolbar as a private member of MainActivity
toolbar.setVisiblity(show ? View.VISIBLE : View.GONE);
// But you can also do this
if (show) {
getSupportActionBar().show();
}
else {
getSupportActionBar().hide();
}
}
And then when you actually want to hide it from your fragment, call it:
((MainActivity)getActivity()).showToolbar(false);
To make the UI change more smooth, I recommend translating it instead of just instantly hiding it. Take a look at the top answer here for inspiration:
android lollipop toolbar: how to hide/show the toolbar while scrolling?
If you don't know how to take care of when to actually show or hide it via scroll logic, take a look at this library which handles a lot for you and also gives examples:
https://github.com/ksoichiro/Android-ObservableScrollView
This is kind of simple.
Just put this code in your toolbar
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"/>
This will do the magic : app:layout_scrollFlags="scroll|enterAlways"
remember to add in your xml the app call xmlns:app="http://schemas.android.com/apk/res-auto"
Check this tutorial: https://guides.codepath.com/android/Handling-Scrolls-with-CoordinatorLayout
Use below code:
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
...>
<android.support.design.widget.AppBarLayout
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"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/rvToDoList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</android.support.design.widget.CoordinatorLayout>
If RecyclerView is in another fragment, then add below line to the View which contain RecyclerView in this CoordinatorLayout.
app:layout_behavior="#string/appbar_scrolling_view_behavior"
Must Use CoordinatorLayout.

Cannot make support bottomsheet not-hideable when in Expanded state

I'm trying to make a bottomsheet using google support library. The goal is to have a sheet that:
Can be hidden programmatically only
Its height is calculated automatically
Is defined statically in xml
So far so good, simple stuff. There is also this promising isHideable() which defaults to false.
But the bottomsheet seems to ignore the isHideable when the sheet is set to STATE_EXPANDED (although its not going to cover the whole screen). The only way to make it unhideable is to set a peek height (which I don't want). Is there a way to have it expanded and not-hideable without setting the height manually (or via layout change triggers)
Here is the (super slim) code used:
Activity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View bottomSheet = findViewById(R.id.bottomsheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setHideable(false);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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="match_parent"
android:fitsSystemWindows="true">
<LinearLayout
android:id="#+id/bottomsheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:behavior_hideable="false"
app:layout_behavior="#string/bottom_sheet_behavior"
android:background="#android:color/white">
<TextView
android:layout_width="match_parent"
android:layout_height="300dp"
android:text=":) :) :)"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
Behavior
The simplest but hackish way I've found so far:
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
bottomSheet.post(new Runnable() {
#Override
public void run() {
behavior.setPeekHeight(bottomSheet.getHeight());
}
});
And of course when there is need to hide it firstly call setHideable(true).
This is just a workaround that might lead to weird behavior.

AppCompat v21 Toolbar changing logo size

I am migrating to the new Toolbar feature in appcompat v21 from the previous action bar. I still want to keep the logo on the top left part of the actionbar (toolbar). For doing I added in my layout the support toolbar and I created a new thene for it.
app:theme="#style/NewToolBarStyle"
I am adding the log programmatically as there is some logic in the app for this.
actionBar.setLogo(R.drawable.myicon);
Referring to my new style (empty for the moment):
<style name="NewToolBarStyle" parent="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
</style>
However the result is showing an image the is too big for what I am looking for, and I am wondering how to reduce the size of the icon.
Is there any way (style, layout or programming) that I can reduce the logo size?
There is no logo icon in material design : http://www.google.com/design/spec/layout/structure.html#, so I suppose this is not well tested scenerio - or simply (broken) by design. You can add ImageView as a child widget of your toolbar and use it to show any image. It will show on the right of all the other internal widgets - like spinner - but list navigation mode is also deprecated.
If you insist on having logo then my workaround for this is to make sure toolbar is of fixed height - this takes care of wrong icon height. Even after that you will have to set setAdjustViewBounds to true on toolbars internal logo ImageView - otherwise it will create large left and right padding.
This is how my toolbar looks like (height set to ?attr/actionBarSize):
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
</android.support.v7.widget.Toolbar>
reference it inside your activity layout using:
<include layout="#layout/toolbar_actionbar"/>
dont change layout_height in include.
The second step is to setAdjustViewBounds(true) on logo icon:
Drawable logo = getDrawable(iconRes);
toolbar.setLogo(logo);
for (int i = 0; i < toolbar.getChildCount(); i++) {
View child = toolbar.getChildAt(i);
if (child != null)
if (child.getClass() == ImageView.class) {
ImageView iv2 = (ImageView) child;
if ( iv2.getDrawable() == logo ) {
iv2.setAdjustViewBounds(true);
}
}
}
Following the suggestiong give by #brightstar I would like to develop further the answer.
The best way to control the size and position of the Logo in the new Toolbar is by actually not using it. The concept is completely different, what you need to do is create a toolbar from scratch. So you need to make a decision, either you use the layout given by the actionBar or include everything new including the title.
If you stop using the logo but you keep using the title you finally will see that the logo is over the title creating and ood situation.
So, an example of what to do is the following:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/action_bar_background"
app:theme="#style/NewToolBarStyle"
android:minHeight="?attr/actionBarSize" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="#+id/text_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="17dp"
android:textSize="20sp"
android:layout_toRightOf="#+id/logo_image"
android:text="#string/app_name"
android:textColor="#color/white" />
<ImageView
android:id="#+id/logo_image"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:scaleType="centerInside" />
</RelativeLayout>
</FrameLayout>
You create this file as my_toolbar.xml. Notice the following details:
I did not include an src of my ImageView because I am changing it dinamically. But works adding it.
I used a relative layout for being able to center the icon and the text.
I need still to include the Home button.
Later on as described by #brightstar you need to include in the top of your layouts by an include, however.... remember to add an id so that you can refere all your other Views to it.
<include layout="#layout/toolbar_sharemup"
android:id="#+id/including" />

How does the Android L contacts app collapse its toolbar?

I've been trying to reproduce the way that the Contacts app on version 5.0 collapses the toolbar when the listview is scrolled.
Gallery of screenshots demonstrating the desired interaction
Note the collapse of the toolbar in stages, where it displays search+last contact, fades last contact, collapses last contact, collapses search, leaving only the tabs.
So far, I have a toolbar sitting above a recyclerview in a LinearLayout, and the toolbar is used as an actionbar, not standalone.
I can't figure out how to intercept the touch event on the recyclerview and make it shrink the toolbar, and then return the scroll event to the recyclerview. I tried putting the entire thing in a scrollview, but then the recyclerview couldn't calculate it's height properly and displayed no content. I tried overriding onscroll on the recyclerview, and found that it will only notify me when a scroll event started, and provide me with the first visible card id.
The way that looks right, but I can't get working for the life of me, is this:
getSupportActionBar().setHideOnContentScrollEnabled(true);
Which returns:
Caused by: java.lang.UnsupportedOperationException: Hide on content scroll is not supported in this action bar configuration.
Using a traditional actionbar, putting a toolbar below it, and setting hideoncontentscrollenabled also didn't work, scrolling never triggered the hide method on the actionbar.
-- edit --
I was able to get hideOnContentScrollEnabled working on a listview with a traditional actionbar, but the behavior is not the same as the contacts app. This is clearly not the method they used-- it simply triggers .hide() on the actionbar when a fling event occurs on a listview, which is notably different from the contacts app, which drags the toolbar along with the scroll event.
-- /edit --
So I abandoned that route, and put fill_parent on the cardview height, and animated a collapse on the toolbar. But how do I trigger it so that it follows the touch event and then returns the touch event to the recyclerview?
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/actionBarSize"
android:background="#color/colorPrimary"
/>
<fragment android:name="me.myapplication.FragmentTab"
android:id="#+id/tab_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
fragment_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="8dp"
android:background="#eeeeee"
>
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
styles.xml
...
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
...
MainActivity.java
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
// Disable the logo in the actionbar, as per material guidelines
toolbar.getMenu().clear();
toolbar.setTitle("My toolbar");
setSupportActionBar(toolbar);
I haven't investigated the source code yet but this guy seems to have made life easy yet enlightening.
https://github.com/ksoichiro/Android-ObservableScrollView
EDIT
Google has just released Android Design Library. Please take a look as it contains all the effects of collapsing toolbars and much more.
Well, I have no idea how they do it, but... why don't you take a peek to the source code? Luckily for us, the Contacts app is still open-source on Android L (others weren't as lucky as Contacts, like Mail, which does not work anymore on L; or Keyboard, which they stopped updating anymore since the launch of their propietary Google Keyboard).
Anyway, here's the source code I think you should look at:
https://github.com/android/platform_packages_apps_contacts/blob/master/src%2Fcom%2Fandroid%2Fcontacts%2Factivities%2FActionBarAdapter.java
Note the method update(boolean skipAnimation) in Line 311, which calls animateTabHeightChange(int start, int end) (Line 437).
My guess is all the magic happens there ;-)
As of June 2015, your desired effect can be accomplished via the so called CollapsingToolbarLayout of the new design support library.
Based on the sample code here, I am figuring that:
the search cardview is child of the toolbar
the missed call cardview belongs to the collapsingtoolbar with the collapseMode attribute set to pin
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="112dp"
android:fitsSystemWindows="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="?attr/actionBarSize"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed|enterAlways">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="false"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways">
<!-- Search layout -->
<android.support.v7.widget.CardView
</android.support.v7.widget.CardView>
</android.support.v7.widget.Toolbar>
<!-- Last call card view-->
<android.support.v7.widget.CardView
app:layout_collapseMode="pin">
</android.support.v7.widget.CardView>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#color/primary_color"
app:layout_scrollFlags="scroll"/>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
No third party library is required now! Android is officially providing library. You can collapse the toolbar and do many other tweaks.
Check this android-developer's blog
And don't forget to add this dependency in your build.gradle file.
compile 'com.android.support:design:22.2.0'
I found this library that seems to do what you're looking for: https://github.com/kmshack/Android-ParallaxHeaderViewPager and this https://github.com/flavienlaurent/NotBoringActionBar
You can play the video to see the behavior: https://www.youtube.com/watch?v=sCP-b0a1x5Y
It might not be the 'new' standard way of doing it with ToolBar, but it might give you an idea by inspecting the code. It seems to attach a OnScrollListener to the scrolling content and then trigger changes on the size of the bar.
For me https://mzgreen.github.io/2015/06/23/How-to-hideshow-Toolbar-when-list-is-scrolling%28part3%29/ has helped. A source code is found here: https://github.com/mzgreen/HideOnScrollExample/tree/master/app/src/main.
A RecycleView in your layout should look like:
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
Note that after starting an application 2 toolbars appear (actionbar and toolbar). So in your activity.java you should write so:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide ActionBar.
supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
getSupportActionBar().hide();
setContentView(R.layout.your_activity_layout);
...
The toolbar is customized as shown here: https://stackoverflow.com/a/26548766/2914140. I mean, it appears without title and any other elements, so you can add them in a layout.
Android's Contact app doesn't have an easy plug-and-play solution that you can grab for use in your own app.
It does a full implementation, essentially doing it the same way you would do it if you were implementing it from scratch. For context, before looking at the code, keep in mind how the views are laid out:
https://github.com/android/platform_packages_apps_contacts/blob/lollipop-release/res/layout/quickcontact_activity.xml
The MultiShrinkScroller is a FrameLayout which intermediates the scrolling behavior, but the main stuff is in a LinearLayout, so reducing the height of the higher views will "scroll" the lower views upwards.
The key file for the implementation is this one:
https://github.com/android/platform_packages_apps_contacts/blob/lollipop-release/src/com/android/contacts/widget/MultiShrinkScroller.java
public void scrollTo(int x, int y) {
final int delta = y - getScroll();
boolean wasFullscreen = getScrollNeededToBeFullScreen() <= 0;
if (delta > 0) {
scrollUp(delta);
} else {
scrollDown(delta);
}
updatePhotoTintAndDropShadow();
updateHeaderTextSizeAndMargin();
//... other stuff
}
private void scrollUp(int delta) {
// Collapse higher views first
if (getTransparentViewHeight() != 0) {
final int originalValue = getTransparentViewHeight();
setTransparentViewHeight(getTransparentViewHeight() - delta);
setTransparentViewHeight(Math.max(0, getTransparentViewHeight()));
delta -= originalValue - getTransparentViewHeight();
}
// Shrink toolbar as needed
final ViewGroup.LayoutParams toolbarLayoutParams
= mToolbar.getLayoutParams();
if (toolbarLayoutParams.height > getFullyCompressedHeaderHeight()) {
final int originalValue = toolbarLayoutParams.height;
toolbarLayoutParams.height -= delta;
toolbarLayoutParams.height = Math.max(toolbarLayoutParams.height,
getFullyCompressedHeaderHeight());
mToolbar.setLayoutParams(toolbarLayoutParams);
delta -= originalValue - toolbarLayoutParams.height;
}
// Finally, scroll content if nothing left to shrink
mScrollView.scrollBy(0, delta);
}
updatePhotoTintAndDropShadow(); and updateHeaderTextSizeAndMargin(); handle the change in tint and text as it gets collapsed so that it turns into the look and feel of a regular ActionBar/ToolBar.
You could grab the MultiShrinkScroller file itself and adapt it for your own use, but there are probably easier implementations nowadays (including those from Android's design library).

Categories

Resources