Merged PR 216546: PeoplePicker: Dropdown polish

- Using Outlook's adjustDropDownPositionAndSize and getMaxAvailableHeight methods in ContactPickerView to resize the drop down to the available space in the view. This makes the list less jumpy, which is most noticeable when it appears above the anchor.
- Switching between portrait and landscape mode no longer dismisses the dropdown nor removes the constraint text. The dropdown also resizes smoothly to adapt. Going from landscape to portrait, the dropdown takes up the full screen, but it does this in Outlook, also.
- Removed the default drop shadow for the dropdown and replaced it with a layer-list drawable that gives it a border along the anchor.
- Refactored some dimens / color naming

Related work items: #670910
This commit is contained in:
Emily Lynam 2019-01-02 22:53:22 +00:00
Родитель 9e9db96d81
Коммит 80dd8257b3
18 изменённых файлов: 144 добавлений и 63 удалений

Просмотреть файл

@ -23,7 +23,10 @@
<activity android:name="com.microsoft.officeuifabricdemo.demos.AvatarViewActivity" />
<activity android:name="com.microsoft.officeuifabricdemo.demos.CalendarViewActivity" />
<activity android:name="com.microsoft.officeuifabricdemo.demos.DateTimePickerDialogActivity" />
<activity android:name="com.microsoft.officeuifabricdemo.demos.PeoplePickerViewActivity" />
<activity
android:name="com.microsoft.officeuifabricdemo.demos.PeoplePickerViewActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:windowSoftInputMode="adjustResize" />
<activity android:name="com.microsoft.officeuifabricdemo.demos.PersonaChipViewActivity" />
<activity android:name="com.microsoft.officeuifabricdemo.demos.PersonaListViewActivity" />
<activity android:name="com.microsoft.officeuifabricdemo.demos.PersonaViewActivity" />

Просмотреть файл

@ -2,24 +2,24 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/people_picker_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:showDividers="middle"
android:divider="@drawable/ms_row_divider">
android:divider="@drawable/ms_row_divider"
android:orientation="vertical"
android:showDividers="middle">
<com.microsoft.officeuifabric.peoplepicker.PeoplePickerView
android:id="@+id/people_picker_select"
app:label="@string/people_picker_select_example"
app:personaChipClickStyle="select"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
app:label="@string/people_picker_select_example"
app:personaChipClickStyle="select" />
<com.microsoft.officeuifabric.peoplepicker.PeoplePickerView
android:id="@+id/people_picker_select_deselect"
app:label="@string/people_picker_select_deselect_example"
app:personaChipClickStyle="select_deselect"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
app:label="@string/people_picker_select_deselect_example"
app:personaChipClickStyle="select_deselect" />
</LinearLayout>

Просмотреть файл

@ -58,7 +58,7 @@ internal class PeoplePickerTextView : TokenCompleteTextView<IPersona> {
}
/**
* Defines what happens when a user clicks on a [personaChip] token.
* Defines what happens when a user clicks on a [personaChip].
*/
var personaChipClickStyle: PeoplePickerPersonaChipClickStyle = PeoplePickerPersonaChipClickStyle.Select
set(value) {

Просмотреть файл

@ -63,13 +63,12 @@ internal class PeoplePickerTextViewAdapter : ArrayAdapter<IPersona>, Filterable
private fun createDivider(): InsetDrawable {
val spacing = PersonaView.getSpacing(context, AvatarSize.LARGE)
val insetDrawable = InsetDrawable(
return InsetDrawable(
ContextCompat.getDrawable(context, R.drawable.ms_row_divider),
spacing.insetLeft,
0,
spacing.cellPadding,
0
)
return insetDrawable
}
}

Просмотреть файл

@ -5,6 +5,8 @@
package com.microsoft.officeuifabric.peoplepicker
import android.content.Context
import android.content.res.Configuration
import android.graphics.Rect
import android.util.AttributeSet
import android.view.ViewGroup
import android.widget.Filter
@ -19,13 +21,10 @@ import kotlinx.android.synthetic.main.view_people_picker.view.*
typealias PeoplePickerPersonaChipClickStyle = TokenCompleteTextView.TokenClickStyle
/**
* [PeoplePickerView] is a customizable [TemplateView] comprised of a label and [PeoplePickerTextView].
* [PeoplePickerView] is a customizable view comprised of a label and [PeoplePickerTextView].
*
* TODO Future work:
* - Handle cases where [pickedPersonas] is modified programmatically.
* - Use Outlook's adjustDropDownPositionAndSize and getMaxAvailableHeight methods in ContactPickerView
* to resize the drop down to the available space in the view. This will make the list less jumpy,
* which is most noticeable when it appears above the [PeoplePickerTextView].
*/
class PeoplePickerView : TemplateView {
/**
@ -177,6 +176,54 @@ class PeoplePickerView : TemplateView {
peoplePickerTextView?.addObject(persona)
}
// Dropdown
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
adjustDropDownHeight()
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
adjustDropDownHeight()
}
private fun adjustDropDownHeight() {
val dropDownHeight = getMaxAvailableHeight()
if (peoplePickerTextView?.dropDownHeight == dropDownHeight)
return
peoplePickerTextView?.dropDownHeight = dropDownHeight
if (peoplePickerTextView?.isPopupShowing == true)
// Force popup layout to refresh
peoplePickerTextView?.showDropDown()
}
/**
* Adapted from Android's PopupWindow.
*/
private fun getMaxAvailableHeight(): Int {
val displayFrame = Rect()
getWindowVisibleDisplayFrame(displayFrame)
val anchorLocationOnScreen = IntArray(2)
getLocationOnScreen(anchorLocationOnScreen)
val anchorTop = anchorLocationOnScreen[1]
val yOffset = resources.getDimension(R.dimen.uifabric_people_picker_dropdown_vertical_offset).toInt()
val distanceToBottom = displayFrame.bottom - (anchorTop + height) - yOffset
val distanceToTop = anchorTop - displayFrame.top + yOffset
var returnedHeight = Math.max(distanceToBottom, distanceToTop)
val background = peoplePickerTextView?.dropDownBackground
if (background != null) {
val backgroundPadding = Rect()
background.getPadding(backgroundPadding)
returnedHeight -= backgroundPadding.top + backgroundPadding.bottom
}
return returnedHeight
}
// Filter
private class PersonaFilter(val view: PeoplePickerView) : Filter() {
@ -193,17 +240,17 @@ class PeoplePickerView : TemplateView {
val availablePersonas = view.availablePersonas
val suggestedPersonas: ArrayList<IPersona>
if (availablePersonas == null)
suggestedPersonas = ArrayList()
else
if (constraint != null) {
suggestedPersonas = when {
availablePersonas == null -> ArrayList()
constraint != null -> {
val searchTerm = constraint.toString().toLowerCase()
val filteredResults = availablePersonas.filter {
it.name.toLowerCase().contains(searchTerm) && !view.pickedPersonas.contains(it)
}
suggestedPersonas = ArrayList(filteredResults)
} else
suggestedPersonas = availablePersonas
ArrayList(filteredResults)
}
else -> availablePersonas
}
return FilterResults().apply {
values = suggestedPersonas
count = suggestedPersonas.size
@ -218,8 +265,7 @@ class PeoplePickerView : TemplateView {
view.peoplePickerTextViewAdapter?.personas = it
}
}
}
else {
} else {
view.peoplePickerTextViewAdapter?.personas = results.values as ArrayList<IPersona>
}
}

Просмотреть файл

@ -164,7 +164,7 @@ class PersonaChipView : TemplateView {
private fun setDisabledState() {
avatarView?.alpha = DISABLED_BACKGROUND_OPACITY
updateStateStyles(R.drawable.persona_chip_background_normal, R.color.uifabric_chip_disabled_text)
updateStateStyles(R.drawable.persona_chip_background_normal, R.color.uifabric_persona_chip_disabled_text)
}
private fun setNormalState() {
@ -173,15 +173,15 @@ class PersonaChipView : TemplateView {
updateCloseIconVisibility(false)
}
if (hasError) {
updateStateStyles(R.drawable.persona_chip_background_normal_error, R.color.uifabric_chip_error_text)
updateStateStyles(R.drawable.persona_chip_background_normal_error, R.color.uifabric_persona_chip_error_text)
} else {
updateStateStyles(R.drawable.persona_chip_background_normal, R.color.uifabric_chip_normal_text)
updateStateStyles(R.drawable.persona_chip_background_normal, R.color.uifabric_persona_chip_normal_text)
}
}
private fun setPressedState() {
updateStateStyles(R.drawable.persona_chip_background_pressed, R.color.uifabric_chip_normal_text)
updateStateStyles(R.drawable.persona_chip_background_pressed, R.color.uifabric_persona_chip_normal_text)
}
private fun setSelectedState() {
@ -189,9 +189,9 @@ class PersonaChipView : TemplateView {
updateCloseIconVisibility(true)
}
if (hasError) {
updateStateStyles(R.drawable.persona_chip_background_active_error, R.color.uifabric_chip_active_text)
updateStateStyles(R.drawable.persona_chip_background_active_error, R.color.uifabric_persona_chip_active_text)
} else {
updateStateStyles(R.drawable.persona_chip_background_active, R.color.uifabric_chip_active_text)
updateStateStyles(R.drawable.persona_chip_background_active, R.color.uifabric_persona_chip_active_text)
}
}

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) 2018. Microsoft Corporation. All rights reserved.-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/people_picker_popup_background_above" android:state_above_anchor="true" />
<item android:drawable="@drawable/people_picker_popup_background_below" />
</selector>

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) 2018. Microsoft Corporation. All rights reserved.-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/ms_row_divider"
android:gravity="bottom" />
<item android:bottom="@dimen/uifabric_divider_height">
<color android:color="@color/uifabric_people_picker_popup_background" />
</item>
</layer-list>

Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) 2018. Microsoft Corporation. All rights reserved.-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/ms_row_divider"
android:gravity="top" />
<item android:top="@dimen/uifabric_divider_height">
<color android:color="@color/uifabric_people_picker_popup_background" />
</item>
</layer-list>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) 2018. Microsoft Corporation. All rights reserved.-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/uifabric_chip_active" />
<solid android:color="@color/uifabric_persona_chip_active" />
<corners android:radius="@dimen/uifabric_corner_radius_2dp" />
</shape>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) 2018. Microsoft Corporation. All rights reserved.-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/uifabric_chip_error_active" />
<solid android:color="@color/uifabric_persona_chip_error_active" />
<corners android:radius="@dimen/uifabric_corner_radius_2dp" />
</shape>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) 2018. Microsoft Corporation. All rights reserved.-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/uifabric_chip_normal" />
<solid android:color="@color/uifabric_persona_chip_normal" />
<corners android:radius="@dimen/uifabric_corner_radius_2dp" />
</shape>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) 2018. Microsoft Corporation. All rights reserved.-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/uifabric_chip_error" />
<solid android:color="@color/uifabric_persona_chip_error" />
<corners android:radius="@dimen/uifabric_corner_radius_2dp" />
</shape>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (c) 2018. Microsoft Corporation. All rights reserved.-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/uifabric_chip_pressed"/>
<solid android:color="@color/uifabric_persona_chip_pressed"/>
<corners android:radius="@dimen/uifabric_corner_radius_2dp" />
</shape>

Просмотреть файл

@ -29,14 +29,16 @@
android:id="@+id/people_picker_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/uifabric_white"
android:background="@color/uifabric_people_picker_text_view_background"
android:gravity="center_vertical"
android:dropDownWidth="match_parent"
android:dropDownVerticalOffset="@dimen/uifabric_people_picker_dropdown_vertical_offset"
android:imeOptions="flagNoExtractUi|actionDone"
android:minHeight="@dimen/uifabric_min_touch_size"
android:paddingTop="@dimen/uifabric_people_picker_token_padding"
android:paddingBottom="@dimen/uifabric_people_picker_token_padding"
android:paddingTop="@dimen/uifabric_people_picker_text_view_padding"
android:paddingBottom="@dimen/uifabric_people_picker_text_view_padding"
android:popupBackground="@drawable/people_picker_popup_background"
android:popupElevation="@dimen/uifabric_people_picker_popup_elevation"
android:textAppearance="@style/TextAppearance.UIFabric.PeoplePickerText"
android:textColorHint="@android:color/transparent" />

Просмотреть файл

@ -5,23 +5,23 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="@dimen/uifabric_chip_height"
android:layout_height="@dimen/uifabric_persona_chip_height"
android:baselineAligned="true"
android:orientation="horizontal"
android:padding="@dimen/uifabric_chip_padding">
android:padding="@dimen/uifabric_persona_chip_padding">
<com.microsoft.officeuifabric.persona.AvatarView
android:id="@+id/persona_chip_avatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/uifabric_chip_spacing"
android:layout_marginEnd="@dimen/uifabric_persona_chip_spacing"
app:avatarSize="xsmall" />
<ImageView
android:id="@+id/persona_chip_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/uifabric_chip_spacing"
android:layout_marginEnd="@dimen/uifabric_persona_chip_spacing"
android:src="@drawable/ms_ic_close"/>
<TextView

Просмотреть файл

@ -47,21 +47,6 @@
<item>#393939</item>
</array>
<!--Chips-->
<color name="uifabric_chip_normal">@color/uifabric_background_gray</color>
<color name="uifabric_chip_normal_text">@color/uifabric_black</color>
<!-- TODO update after design adds #0D000000 to toolkit -->
<color name="uifabric_chip_pressed">#0D000000</color>
<color name="uifabric_chip_active">@color/uifabric_primary</color>
<color name="uifabric_chip_active_text">@color/uifabric_white</color>
<!-- TODO update after design adds #FFF3F4 to toolkit -->
<color name="uifabric_chip_error">#FFF3F4</color>
<!-- TODO update after design adds #E8484C to toolkit -->
<color name="uifabric_chip_error_active">#E8484C</color>
<!-- TODO update after design adds #A80000 to toolkit -->
<color name="uifabric_chip_error_text">#A80000</color>
<color name="uifabric_chip_disabled_text">@color/uifabric_gray</color>
<!--CalendarView-->
<color name="uifabric_calendar_week_header_background">@color/uifabric_primary</color>
<color name="uifabric_calendar_week_heading_week_day_text">@color/uifabric_gray</color>
@ -86,6 +71,25 @@
<color name="uifabric_number_picker_default_accent">@color/uifabric_primary</color>
<color name="uifabric_number_picker_default_text">@color/uifabric_gray</color>
<!--PeoplePicker-->
<color name="uifabric_people_picker_popup_background">@color/uifabric_white</color>
<color name="uifabric_people_picker_text_view_background">@color/uifabric_white</color>
<!--Persona Chip-->
<color name="uifabric_persona_chip_normal">@color/uifabric_background_gray</color>
<color name="uifabric_persona_chip_normal_text">@color/uifabric_black</color>
<!-- TODO update after design adds #0D000000 to toolkit -->
<color name="uifabric_persona_chip_pressed">#0D000000</color>
<color name="uifabric_persona_chip_active">@color/uifabric_primary</color>
<color name="uifabric_persona_chip_active_text">@color/uifabric_white</color>
<!-- TODO update after design adds #FFF3F4 to toolkit -->
<color name="uifabric_persona_chip_error">#FFF3F4</color>
<!-- TODO update after design adds #E8484C to toolkit -->
<color name="uifabric_persona_chip_error_active">#E8484C</color>
<!-- TODO update after design adds #A80000 to toolkit -->
<color name="uifabric_persona_chip_error_text">#A80000</color>
<color name="uifabric_persona_chip_disabled_text">@color/uifabric_gray</color>
<!--Shared-->
<color name="uifabric_divider">@color/uifabric_border_gray</color>

Просмотреть файл

@ -40,8 +40,9 @@
<dimen name="uifabric_number_picker_padding_right">8dp</dimen>
<!--PeoplePicker-->
<dimen name="uifabric_people_picker_token_padding">6dp</dimen>
<dimen name="uifabric_people_picker_popup_elevation">0dp</dimen>
<dimen name="uifabric_people_picker_dropdown_vertical_offset">0dp</dimen>
<dimen name="uifabric_people_picker_text_view_padding">6dp</dimen>
<!--Persona-->
<dimen name="uifabric_persona_horizontal_spacing">16dp</dimen>
@ -51,9 +52,9 @@
<dimen name="uifabric_persona_label_spacing">8dp</dimen>
<!--PersonaChip-->
<dimen name="uifabric_chip_height">32dp</dimen>
<dimen name="uifabric_chip_padding">6dp</dimen>
<dimen name="uifabric_chip_spacing">6dp</dimen>
<dimen name="uifabric_persona_chip_height">32dp</dimen>
<dimen name="uifabric_persona_chip_padding">6dp</dimen>
<dimen name="uifabric_persona_chip_spacing">6dp</dimen>
<!--Shared-->
<dimen name="uifabric_divider_height">.5dp</dimen>