Merged PR 251892: Snackbar: Bug fixes and polish for icon variant

- Fix a bug so that we can use `Snackbar`s in `RecyclerView`s with `findSuitableParent` method borrowed from android (discovered this while working on `ListItemView`)
- Add single line Snackbar with icon variant to the demo and fix bugs so that the icon and text are centered properly
- Give a default duration (per design and pm request)
- Note which duration is used in the demo button text.

| Single-line with icon | Single-line with icon and action |
| ------------- |:-------------:|
|![Screenshot_1554738893.png](https://onedrive.visualstudio.com/4dcbf0bc-c3cd-49c8-a7c3-ec1924691d9b/_apis/git/repositories/32fa6338-45ea-42a0-aca0-484938e1962a/pullRequests/251892/attachments/Screenshot_1554738893.png) | ![Screenshot_1554738897.png](https://onedrive.visualstudio.com/4dcbf0bc-c3cd-49c8-a7c3-ec1924691d9b/_apis/git/repositories/32fa6338-45ea-42a0-aca0-484938e1962a/pullRequests/251892/attachments/Screenshot_1554738897.png) |
| Multi-line with icon | Multi-line with icon and action |
|![Screenshot_1554738900.png](https://onedrive.visualstudio.com/4dcbf0bc-c3cd-49c8-a7c3-ec1924691d9b/_apis/git/repositories/32fa6338-45ea-42a0-aca0-484938e1962a/pullRequests/251892/attachments/Screenshot_1554738900.png) | ![Screenshot_1554738905.png](https://onedrive.visualstudio.com/4dcbf0bc-c3cd-49c8-a7c3-ec1924691d9b/_apis/git/repositories/32fa6338-45ea-42a0-aca0-484938e1962a/pullRequests/251892/attachments/Screenshot_1554738905.png) |

Related work items: #706313
This commit is contained in:
Emily Lynam 2019-04-08 19:11:34 +00:00
Родитель 475e3f07af
Коммит 665dc1ccf4
9 изменённых файлов: 163 добавлений и 52 удалений

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

@ -21,56 +21,79 @@ class SnackbarActivity : DemoActivity(), View.OnClickListener {
super.onCreate(savedInstanceState)
btn_snackbar_single_line.setOnClickListener(this)
btn_snackbar_multi_line.setOnClickListener(this)
btn_snackbar_announcement.setOnClickListener(this)
btn_snackbar_multi_line_action.setOnClickListener(this)
btn_snackbar_multi_line_long_action.setOnClickListener(this)
btn_snackbar_single_line_icon.setOnClickListener(this)
btn_snackbar_single_line_action.setOnClickListener(this)
btn_snackbar_single_line_action_icon.setOnClickListener(this)
btn_snackbar_multi_line.setOnClickListener(this)
btn_snackbar_multi_line_icon.setOnClickListener(this)
btn_snackbar_multi_line_action.setOnClickListener(this)
btn_snackbar_multi_line_action_icon.setOnClickListener(this)
btn_snackbar_multi_line_long_action.setOnClickListener(this)
btn_snackbar_announcement.setOnClickListener(this)
}
override fun onClick(v: View) {
when (v.id) {
R.id.btn_snackbar_single_line -> Snackbar.make(root_view, getString(R.string.snackbar_single_line), Snackbar.LENGTH_SHORT).show()
R.id.btn_snackbar_single_line ->
Snackbar.make(root_view, getString(R.string.snackbar_single_line)).show()
R.id.btn_snackbar_multi_line -> Snackbar.make(root_view, getString(R.string.snackbar_multi_line), Snackbar.LENGTH_LONG).show()
R.id.btn_snackbar_single_line_icon ->
Snackbar.make(root_view, getString(R.string.snackbar_single_line))
.setIcon(R.drawable.ic_done_white)
.show()
R.id.btn_snackbar_single_line_action -> {
val snackbar = Snackbar.make(root_view, getString(R.string.snackbar_single_line), Snackbar.LENGTH_SHORT)
snackbar.setAction(getString(R.string.snackbar_action), View.OnClickListener {
R.id.btn_snackbar_single_line_action ->
Snackbar.make(root_view, getString(R.string.snackbar_single_line))
.setAction(getString(R.string.snackbar_action), View.OnClickListener {
// handle click here
})
snackbar.show()
}
.show()
R.id.btn_snackbar_multi_line_action -> {
val snackbar = Snackbar.make(root_view, getString(R.string.snackbar_multi_line), Snackbar.LENGTH_INDEFINITE)
snackbar.setAction(getString(R.string.snackbar_action), View.OnClickListener {
R.id.btn_snackbar_single_line_action_icon ->
Snackbar.make(root_view, getString(R.string.snackbar_single_line))
.setIcon(R.drawable.ic_done_white)
.setAction(getString(R.string.snackbar_action), View.OnClickListener {
// handle click here
})
snackbar.show()
}
.show()
R.id.btn_snackbar_multi_line_long_action -> {
val snackbar = Snackbar.make(root_view, getString(R.string.snackbar_multi_line), Snackbar.LENGTH_INDEFINITE)
snackbar.setAction(getString(R.string.snackbar_action_long), View.OnClickListener {
R.id.btn_snackbar_multi_line ->
Snackbar.make(root_view, getString(R.string.snackbar_multi_line), Snackbar.LENGTH_LONG).show()
R.id.btn_snackbar_multi_line_icon ->
Snackbar.make(root_view, getString(R.string.snackbar_multi_line), Snackbar.LENGTH_LONG)
.setIcon(R.drawable.ic_done_white)
.show()
R.id.btn_snackbar_multi_line_action ->
Snackbar.make(root_view, getString(R.string.snackbar_multi_line), Snackbar.LENGTH_INDEFINITE)
.setAction(getString(R.string.snackbar_action), View.OnClickListener {
// handle click here
})
snackbar.show()
}
.show()
R.id.btn_snackbar_announcement -> {
val snackbar = Snackbar.make(
root_view,
getString(R.string.snackbar_announcement),
Snackbar.LENGTH_INDEFINITE,
Snackbar.Style.ANNOUNCEMENT
)
snackbar.setIcon(R.drawable.ms_ic_birthday)
snackbar.setAction(getString(R.string.snackbar_action), View.OnClickListener {
R.id.btn_snackbar_multi_line_action_icon ->
Snackbar.make(root_view, getString(R.string.snackbar_multi_line))
.setIcon(R.drawable.ic_done_white)
.setAction(getString(R.string.snackbar_action), View.OnClickListener {
// handle click here
})
snackbar.show()
}
.show()
R.id.btn_snackbar_multi_line_long_action ->
Snackbar.make(root_view, getString(R.string.snackbar_multi_line))
.setAction(getString(R.string.snackbar_action_long), View.OnClickListener {
// handle click here
})
.show()
R.id.btn_snackbar_announcement ->
Snackbar.make(root_view, getString(R.string.snackbar_announcement), style = Snackbar.Style.ANNOUNCEMENT)
.setIcon(R.drawable.ic_birthday)
.setAction(getString(R.string.snackbar_action), View.OnClickListener {
// handle click here
})
.show()
}
}
}

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

@ -5,6 +5,6 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:height="@dimen/default_layout_margin" />
<size android:height="@dimen/default_view_margin" />
<solid android:color="@android:color/transparent" />
</shape>

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

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Microsoft Corporation. All rights reserved.
~ Licensed under the MIT License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:pathData="M9,16.17l-4.17,-4.17l-1.42,1.41l5.59,5.59l12,-12l-1.41,-1.41z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

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

@ -19,10 +19,10 @@
android:text="@string/snackbar_button_single_line" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_snackbar_multi_line"
android:id="@+id/btn_snackbar_single_line_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/snackbar_button_multi_line" />
android:text="@string/snackbar_button_single_line_icon" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_snackbar_single_line_action"
@ -30,12 +30,36 @@
android:layout_height="wrap_content"
android:text="@string/snackbar_button_single_line_action" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_snackbar_single_line_action_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/snackbar_button_single_line_action_icon" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_snackbar_multi_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/snackbar_button_multi_line" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_snackbar_multi_line_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/snackbar_button_multi_line_icon" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_snackbar_multi_line_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/snackbar_button_multi_line_action" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_snackbar_multi_line_action_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/snackbar_button_multi_line_action_icon" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_snackbar_multi_line_long_action"
android:layout_width="wrap_content"

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

@ -133,12 +133,16 @@
<string name="snackbar_action">Action</string>
<string name="snackbar_action_long">Long Text Action</string>
<string name="snackbar_announcement">This is an announcement snackbar. Its used for communicating new features.</string>
<string name="snackbar_button_single_line">Single-line</string>
<string name="snackbar_button_multi_line">Multi-line</string>
<string name="snackbar_button_single_line_action">Single-line with action</string>
<string name="snackbar_button_multi_line_action">Multi-line with action</string>
<string name="snackbar_button_multi_line_action_long">Multi-line with long action text</string>
<string name="snackbar_button_announcement">Announcement style</string>
<string name="snackbar_button_single_line">Single-line, short</string>
<string name="snackbar_button_single_line_icon">Single-line with icon, short</string>
<string name="snackbar_button_single_line_action">Single-line with action, short</string>
<string name="snackbar_button_single_line_action_icon">Single-line with action and icon, short</string>
<string name="snackbar_button_multi_line">Multi-line, long</string>
<string name="snackbar_button_multi_line_icon">Multi-line with icon, long</string>
<string name="snackbar_button_multi_line_action">Multi-line with action, indefinite</string>
<string name="snackbar_button_multi_line_action_icon">Multi-line with action and icon, short</string>
<string name="snackbar_button_multi_line_action_long">Multi-line with long action text, short</string>
<string name="snackbar_button_announcement">Announcement style, short</string>
<string name="snackbar_multi_line">This is a multi-line snackbar. Max lines are set to two, the rest of the text will truncate.
Lorem ipsum dolor sit amet consectetur adipiscing elit. </string>
<string name="snackbar_single_line">Single-line snackbar</string>

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

@ -7,11 +7,13 @@ package com.microsoft.officeuifabric.snackbar
import android.support.annotation.DrawableRes
import android.support.design.widget.BaseTransientBottomBar
import android.support.design.widget.CoordinatorLayout
import android.support.v4.content.ContextCompat
import android.support.v7.widget.AppCompatButton
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
@ -31,7 +33,9 @@ class Snackbar : BaseTransientBottomBar<Snackbar> {
const val LENGTH_SHORT: Int = BaseTransientBottomBar.LENGTH_SHORT
const val LENGTH_LONG: Int = BaseTransientBottomBar.LENGTH_LONG
fun make(parent: ViewGroup, text: CharSequence, duration: Int, style: Style = Style.REGULAR): Snackbar {
fun make(view: View, text: CharSequence, duration: Int = LENGTH_SHORT, style: Style = Style.REGULAR): Snackbar {
val parent = findSuitableParent(view) ?:
throw IllegalArgumentException("No suitable parent found from the given view. Please provide a valid view.")
val content = LayoutInflater.from(parent.context).inflate(R.layout.view_snackbar, parent, false)
val snackbar = Snackbar(parent, content, ContentViewCallback(content))
snackbar.duration = duration
@ -39,6 +43,36 @@ class Snackbar : BaseTransientBottomBar<Snackbar> {
snackbar.setText(text)
return snackbar
}
/**
* This is adapted from android.support.design.widget.snackbar
* It ensures we can use Snackbars in complex ViewGroups like RecyclerView.
*/
private fun findSuitableParent(view: View): ViewGroup? {
var currentView: View? = view
var fallbackParent: ViewGroup? = null
do {
if (currentView is CoordinatorLayout)
// We've found a CoordinatorLayout, use it
return currentView
if (currentView is FrameLayout)
if (currentView.id == android.R.id.content)
// If we've hit the decor content view, then we didn't find a CoL in the
// hierarchy, so use it.
return currentView
else
// It's not the content view but we'll use it as our fallback
fallbackParent = currentView
// Else, we will loop and crawl up the view hierarchy and try to find a parent
currentView = currentView?.parent as? View
} while (currentView != null)
// If we reach here then we didn't find a CoL or a suitable content view so we'll fallback
return fallbackParent
}
}
/**
@ -101,14 +135,20 @@ class Snackbar : BaseTransientBottomBar<Snackbar> {
updateBackground()
layoutTextAndActionButton()
val iconImageViewLayoutParams = iconImageView.layoutParams as RelativeLayout.LayoutParams
when (style) {
Style.REGULAR -> {
actionButtonView.setTextColor(ContextCompat.getColor(context, R.color.uifabric_snackbar_action_text))
iconImageViewLayoutParams.topMargin = context.resources.getDimension(R.dimen.uifabric_snackbar_icon_inset_regular).toInt()
iconImageViewLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL)
}
Style.ANNOUNCEMENT -> {
actionButtonView.setTextColor(ContextCompat.getColor(context, R.color.uifabric_snackbar_action_text_announcement))
iconImageViewLayoutParams.topMargin = context.resources.getDimension(R.dimen.uifabric_snackbar_content_inset).toInt()
iconImageViewLayoutParams.removeRule(RelativeLayout.CENTER_VERTICAL)
}
}
iconImageView.layoutParams = iconImageViewLayoutParams
}
private fun layoutTextAndActionButton() {
@ -120,12 +160,14 @@ class Snackbar : BaseTransientBottomBar<Snackbar> {
if (textWidth > context.resources.getDimension(R.dimen.uifabric_snackbar_action_text_wrapping_width) || style == Style.ANNOUNCEMENT) {
// Action button moves to the bottom of the root view
textLayoutParams.removeRule(RelativeLayout.START_OF)
textLayoutParams.removeRule(RelativeLayout.CENTER_VERTICAL)
textLayoutParams.marginEnd = inset
buttonLayoutParams.addRule(RelativeLayout.BELOW, snackbar_text)
actionButtonView.setPaddingRelative(inset, inset, inset, inset)
} else {
// Action button moves to the end of the text view
textLayoutParams.addRule(RelativeLayout.START_OF, snackbar_action)
textLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL)
textLayoutParams.bottomMargin = inset
if (actionButtonView.text.isNullOrEmpty())
textLayoutParams.marginEnd = inset

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

@ -16,7 +16,6 @@
android:layout_height="@dimen/uifabric_snackbar_announcement_icon_size"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="@dimen/uifabric_snackbar_content_inset"
android:layout_marginTop="@dimen/uifabric_snackbar_content_inset"
android:visibility="gone" />
<TextView

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

@ -82,6 +82,7 @@
<dimen name="uifabric_snackbar_background_inset">8dp</dimen>
<dimen name="uifabric_snackbar_background_corner_radius">4dp</dimen>
<dimen name="uifabric_snackbar_content_inset">@dimen/uifabric_content_inset</dimen>
<dimen name="uifabric_snackbar_icon_inset_regular">12dp</dimen>
<!--Tooltip-->
<dimen name="uifabric_tooltip_max_width">176dp</dimen>