Ответ 1
Я работаю над решением этого в прошлом > 48 часов (у меня есть дополнительное время, не обвиняйте меня), и я могу сказать вам это точно:
- Использование темы AppCompat и обычного
Spinner
дает вам рябь для свободной (yay!). Если у вас есть пользовательскийSpinner
, не забудьте расширитьAppCompatSpinner
, и вы получите неплохую тематику. ЦитированиеAppCompatSpinner
javadoc:
A Spinner, поддерживающий совместимые функции на старой версии платформы, включая:
- Позволяет использовать динамический оттенок фона с помощью методов оттенков фона в ViewCompat.
- Позволяет установить оттенок фона с использованием backgroundTint и backgroundTintMode.
- Позволяет настраивать тему всплывающих окон, используя popupTheme.
Это будет автоматически использоваться, когда вы используете Spinner в своих макетах. Вам нужно будет только вручную использовать этот класс при написании пользовательских представлений.
-
Существует способ no получить
PopupWindow
, который отображается, расширяя класс ЛЮБОЙ. Есть много вложенных классов, которые способствуют этой функции (спойлер: они в основном частные). -
Вы можете настроить переходы ввода и выхода
PopupWindow
... статически в своей теме (woohoo!). В настоящее время я использую AppCompat v23 и выполняю следующее исследование, которое я нашел:-
Стиль, который настраивает
ListPopupWindow
LOLLIPOP и выше<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>
-
Стиль, который настраивает его перед 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>
-
И это то, что вы задали в своей теме:
// From the constructor listPopupWindowStyle is the // theme attribute you're looking for. public ListPopupWindow(Context context, AttributeSet attrs) { this(context, attrs, R.attr.listPopupWindowStyle); }
-
Тем не менее, я все еще в процессе получения вашей специфики, но я решаю ее с помощью клонирования 2 класса: AppCompatSpinner
и ListPopupWindow
и добавления общедоступного getPopup()
getter к клонированному ListPopupWindow
коду, поэтому он доступен в моем клонированном AppCompatSpinner
. Это открывает пару возможностей. Примером может служить мой метод centerPopup()
, который должен сдвигать положение выложенного всплывающего окна на основе центров spinnerItem (выбранного элемента, который отображается в представлении spinner) и spinnerDropdownItem (отдельные представления, которые отображаются как элементы списка в падать). Метод centerPopup() затем вызывается в DropdownPopup.show()
сразу после вызова 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();
}
Если возвращается правильный listItemHeight, всплывающее окно должно появляться не только над счетчиком, но и в текстовых центрах. (Могут быть отключены некоторые пиксели из-за проблем с фоном и дополнением, но они могут быть решены).
После центрирования следующий шаг будет состоять в том, чтобы прокрутить dropDownList selectedPosition View
до центра PopupWindow
и соответствующим образом обновить yoff
Y-offset.
Атрибут popupEnterTransition ограничивается только LOLLIPOP
, но если это не проблема, вы можете вставить туда масштабный переход, который должен получить необходимый эффект. Я не пробовал это, но я также думаю, что лучшая анимация будет эффектом раскрывать от центра прядильщика (это похоже на видео с вашего specs).
Но все это хорошо... в теории x_x lol