I just need something pretty simple. Can't find any guide/resource online that will help me to achieve the following behaviour:
So there are 3 things:
Any help is appreciated .
EDIT
The ripple is actually a straight forward thing that can be found in the docs. The scale up animation of the popup dropdown is what interesting me the most. If I only could get a reference to that popup , I could animate it however I want... Ideas anybody ?
I've been working on a solution to this for the past >48hours (I have some extra time don't blame me) and I can tell you these for sure:
Spinner
gives you the ripples for free (yay!). If you have a custom Spinner
make sure to extend AppCompatSpinner
instead and you get some good theming. Quoting the AppCompatSpinner
javadoc:A Spinner which supports compatible features on older version of the platform, including:
- Allows dynamic tint of it background via the background tint methods in ViewCompat.
- Allows setting of the background tint using backgroundTint and backgroundTintMode.
- Allows setting of the popups theme using popupTheme.
This will automatically be used when you use Spinner in your layouts. You should only need to manually use this class when writing custom views.
There is no way to retrieve the PopupWindow
that displays by extending ANY class. There are a lot of nested classes that contribute to the feature (spoiler: They are mostly private).
You can customize the enter and exit transitions of the PopupWindow
...statically in your theme (woohoo!). I'm currently using AppCompat v23 and doing some investigation i found:
The style that customizes ListPopupWindow
LOLLIPOP and above
<style name="Widget.Material.ListPopupWindow">
<item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
<item name="popupBackground">@drawable/popup_background_material</item>
<item name="popupElevation">@dimen/floating_window_z</item>
<item name="popupAnimationStyle">@empty</item>
<item name="popupEnterTransition">@transition/popup_window_enter</item>
<item name="popupExitTransition">@transition/popup_window_exit</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
<item name="dropDownWidth">wrap_content</item>
</style>
The style that customizes it pre-LOLLIPOP:
<style name="Base.Widget.AppCompat.ListPopupWindow" parent="">
<item name="android:dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
<item name="android:popupBackground">@drawable/abc_popup_background_mtrl_mult</item>
<item name="android:dropDownVerticalOffset">0dip</item>
<item name="android:dropDownHorizontalOffset">0dip</item>
<item name="android:dropDownWidth">wrap_content</item>
</style>
And this is what you set in your Theme:
// From the constructor listPopupWindowStyle is the
// theme attribute you're looking for.
public ListPopupWindow(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.listPopupWindowStyle);
}
That said, I'm still in the process of getting your specifics but I'm solving it by cloning 2 classes: AppCompatSpinner
and ListPopupWindow
and adding a public getPopup()
getter to the cloned ListPopupWindow
code so its accessible in my cloned AppCompatSpinner
. This opens up a couple of opportunities. An example is my centerPopup()
method which should shift the position of the laid out popup based on the centers of the spinnerItem (the selected item that shows in the spinner view itself) and the spinnerDropdownItem (individual views that show as list items in the drop down). The centerPopup() method is then called in DropdownPopup.show()
right after the call to super.show()
private void centerPopup(boolean updateListSelection) {
boolean aboveAnchor = getPopup().isAboveAnchor();
int[] spinnerLocation = new int[2];
int[] popupLocation = new int[2];
ListView listView = getListView();
/*
Popup is anchored at spinner TOP LEFT when it is set to overlap else at BOTTOM LEFT
Also seems the windowlayoutparams generated for popup is wrapcontent for width and height
As a result popup locationOnScreen returns [0, 0] which is relative to the window.
We can take it as relative to spinner location and add spinnerLocation X value to give
left edge of popup
*/
MaterialSpinner.this.getLocationInWindow(spinnerLocation);
int spMidX = spinnerLocation[0] + (MaterialSpinner.this.getWidth() / 2);
int spMidY = spinnerLocation[1] + (MaterialSpinner.this.getHeight() / 2);
Rect spinnerBgdPadding = new Rect();
MaterialSpinner.this.getBackground().getPadding(spinnerBgdPadding);
// ----- BUG - returns erroneous height
// Ideally should measure one of the drop down list children and give a height
// exactly as it wouldwhen laid out eventually.
// Works only for lists with homogenously tall content
View child = listView.getAdapter().getView(0, null, listView);
child.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
child.measure(
MeasureSpec.makeMeasureSpec(listView.getWidth() - listView.getPaddingLeft() - listView.getPaddingRight(), MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
);
int listItemHeight = child.getMeasuredHeight();
// ----- /BUG
getPopup().getContentView().getLocationInWindow(popupLocation);
int popMidX = spinnerLocation[0] + (getPopup().getWidth()) / 2;
int popMidY = spinnerLocation[1] + (listItemHeight / 2);
int hoff = getHorizontalOffset();
int voff = getVerticalOffset();
int xoff = spMidX - popMidX - hoff - spinnerBgdPadding.left;
int yoff = spMidY - popMidY - voff;
getPopup().update(spinnerLocation[0] + xoff, spinnerLocation[1] + yoff, -1, -1, true);
if (updateListSelection)
listView.setSelectionFromTop(MaterialSpinner.this.getSelectedItemPosition(), 0)
;
// getPopup().update(MaterialSpinner.this, xoff, yoff, -1, -1);
// int numVisItems = listView.getLastVisiblePosition() - getFirstVisiblePosition();
}
If the correct listItemHeight is returned the popup window should not only appear over the the spinner but the text centers should align too. (Might be off by some pixels due to background and padding related issues but they can be solved).
Once centered, the next step would be to scroll the dropDownList selectedPosition View
to the center of the popupWindow
and update the yoff
Y-offset accordingly.
The popupEnterTransition attribute limits to only LOLLIPOP
but if that isnt a problem, you can insert your scale up transition there and that should get you the effect you want. I haven't tried it however but I also think a better animation would be a reveal effect from the spinner center (it looks like that from your specs video).
But all these are good...in theory x_x lol
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With