您的位置:首页 > 移动开发 > Android开发

Android Snackbar使用详解

2016-12-24 14:20 585 查看
一、Snackbar是什么鬼

Snackbar是属于design包下的,功能类似于Toast的一种轻量级反馈消息,Snackbar是从底部弹出消息的。

二、Snackbar长什么样的

这就是Snackbar,很简单,左边一个TextView,右边一个Button。



三、Snackbar的基本使用。
(一)最简单的用法
使用前先导入design包,
android studio:compile 'com.android.support:design:25.0.1'。
eclipse:导入sdk\extras\android\support\design这个library,在主项目中引用它,如果没有就打开SDK Manager,找到extras,下载最新的Android Support Library。
Snackbar的用法和Toast很像,有个make()的静态方法,就类似Toast的makeText()那样使用。
public static Snackbar make(@NonNull View view, @NonNull CharSequence text, @Duration int duration)
public static Snackbar make(@NonNull View view, @StringRes int resId, @Duration int duration)
参数一:view就是通过这个view找到合适Snackbar的父容器,
参数二:text和resId就是要显示的内容,
参数三:duration就是显示的时间,多久之后消失,有LENGTH_SHORT(1500毫秒)、LENGTH_LONG(2750毫秒)、LENGTH_INDEFINITE(无限期显示)。
Snackbar有个show()方法就是显示出Snackbar的,像Toast也有。
使用的时候可以这样,
Button _ShowSnackBar = (Button) findViewById(R.id.show_snackbar);
_ShowSnackBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "我就是Snackbar!", Snackbar.LENGTH_LONG).show();
}
});




(二)添加右边的按钮
Snackbar的右边有个Button,可以在Snackbar弹出来的时候按下做一些Action,通过setAction()方法设置。
Snackbar setAction(CharSequence text, final View.OnClickListener listener)
Snackbar setAction(@StringRes int resId, View.OnClickListener listener)


参数一:text和resId就是Button的text,



参数二:listener就是Button的点击事件,点击Button后Snackbar会消失,即使设置了LENGTH_INDEFINITE。
Button _ShowSnackBar = (Button) findViewById(R.id.show_snackbar);
_ShowSnackBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "我就是Snackbar!", Snackbar.LENGTH_INDEFINITE)
.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "我是通过Snackbar弹出来的!", Toast.LENGTH_SHORT).show();
}
}).show();
}
});
(三)显示和隐藏时的回调 在显示Snackbar或隐藏Snackbar时需要做一些事情,这时候就要用到Callback了,通过setCallback()方法,实现Snackbar.Callback这个抽象类,里面有onDismissed()和onShown()两个抽象方法,onShown()是显示的时候调用,onDismissed()在隐藏的时候调用。
Snackbar.make(view, "我就是Snackbar!", Snackbar.LENGTH_LONG)
.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View v) {

}
})
.setCallback(new Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
Toast.makeText(MainActivity.this, "onDismissed", Toast.LENGTH_SHORT).show();
}

@Override
public void onShown(Snackbar snackbar) {
Toast.makeText(MainActivity.this, "onShown", Toast.LENGTH_SHORT).show();
}
})
.show();



四、换个颜色
Snackbar提供了对Button的text的颜色设置的方法setActionTextColor(),
Snackbar.make(view, "我就是Snackbar!", Snackbar.LENGTH_SHORT)
.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View v) {

}
}).setActionTextColor(ColorStateList.valueOf(0xFFFFFF66))
.show();



但是Snackbar对默认背景颜色效果不满意怎么办,能不能换个颜色,行,You happy jiu ok。
我们先来看看Snackbar的布局先,在Snackbar的构造方法里,
private Snackbar(ViewGroup parent) {
mTargetParent = parent;
mContext = parent.getContext();

ThemeUtils.checkAppCompatTheme(mContext);

LayoutInflater inflater = LayoutInflater.from(mContext);
mView = (SnackbarLayout) inflater.inflate(
R.layout.design_layout_snackbar, mTargetParent, false);

mAccessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
}

我们可以看到Snackbar使用design_layout_snackbar这个布局文件,然后转为SnackbarLayout,赋值给mView,我们先看
design_layout_snackbar的布局文件吧,

<view xmlns:android="http://schemas.android.com/apk/res/android"
class="android.support.design.widget.Snackbar$SnackbarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
style="@style/Widget.Design.Snackbar" />
原来就是个View,class="android.support.design.widget.Snackbar$SnackbarLayout",走,去看看SnackbarLayout,
public SnackbarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SnackbarLayout);
mMaxWidth = a.getDimensionPixelSize(R.styleable.SnackbarLayout_android_maxWidth, -1);
mMaxInlineActionWidth = a.getDimensionPixelSize(
R.styleable.SnackbarLayout_maxActionInlineWidth, -1);
if (a.hasValue(R.styleable.SnackbarLayout_elevation)) {
ViewCompat.setElevation(this, a.getDimensionPixelSize(
R.styleable.SnackbarLayout_elevation, 0));
}
a.recycle();

setClickable(true);

LayoutInflater.from(context).inflate(R.layout.design_layout_snackbar_include, this);

ViewCompat.setAccessibilityLiveRegion(this,
ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
ViewCompat.setImportantForAccessibility(this,
ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);

ViewCompat.setFitsSystemWindows(this, true);
ViewCompat.setOnApplyWindowInsetsListener(this,
new android.support.v4.view.OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(),
v.getPaddingRight(), insets.getSystemWindowInsetBottom());
return insets;
}
});
}
哈,在构造方法中我们可以看到inflate的是design_layout_snackbar_include,原来布局文件在这加载,看看去,
<merge xmlns:android="http://schemas.android.com/apk/res/android">

<TextView
android:id="@+id/snackbar_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="@dimen/design_snackbar_padding_vertical"
android:paddingBottom="@dimen/design_snackbar_padding_vertical"
android:paddingLeft="@dimen/design_snackbar_padding_horizontal"
android:paddingRight="@dimen/design_snackbar_padding_horizontal"
android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
android:maxLines="@integer/design_snackbar_text_max_lines"
android:layout_gravity="center_vertical|left|start"
android:ellipsize="end"
android:textAlignment="viewStart"/>

<Button
android:id="@+id/snackbar_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/design_snackbar_extra_spacing_horizontal"
android:layout_marginStart="@dimen/design_snackbar_extra_spacing_horizontal"
android:layout_gravity="center_vertical|right|end"
android:minWidth="48dp"
android:visibility="gone"
android:textColor="?attr/colorAccent"
style="?attr/borderlessButtonStyle"/>

</merge>
就是一个TextView和一个Button,都带有id,我们在回过来看看Snackbar类,有个getView()方法,返回的是mView,
public View getView() {
return mView;
}
现在mView我们有了,两个控件的id我们也有了,你说该怎么办呢,findViewById()啊。
Button _ShowSnackBar = (Button) findViewById(R.id.show_snackbar);
_ShowSnackBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar _Snackbar = Snackbar.make(view, "我是颜色不一样的Snackbar!", Snackbar.LENGTH_SHORT);
_Snackbar.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View v) {

}
});
View _RootView = _Snackbar.getView();
TextView _Text = (TextView) _Snackbar.getView().findViewById(R.id.snackbar_text);
Button _Action = (Button) _Snackbar.getView().findViewById(R.id.snackbar_action);
_RootView.setBackgroundColor(ColorStateList.valueOf(0xFF99CCFF).getDefaultColor());
_Text.setTextColor(ColorStateList.valueOf(0xFFFFFFFF));
_Action.setTextColor(ColorStateList.valueOf(0xFFFFFF66));
_Snackbar.show();
}
});



其实view都有了很多事都可以做的,包括改变显示动画等等。

五、动画
如果想把动画改成从左边进右边出的行不行?行,你喜欢就好。
snackbar_in_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000">
<translate android:fromXDelta="-105%p" android:toXDelta="0" />
</set>

snackbar_out_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000">
<translate android:fromXDelta="0" android:toXDelta="200%p" />
</set>
private void snackbarInAnim(final Snackbar pSnackbar, final View pView) {
Animation _Anim = AnimationUtils.loadAnimation(pView.getContext(),
R.anim.snackbar_in_anim);
_Anim.setInterpolator(new FastOutSlowInInterpolator());
_Anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
snackbarOutAnim(pSnackbar, pView);
}
@Override
public void onAnimationStart(Animation animation) {}

@Override
public void onAnimationRepeat(Animation animation) {}
});
pView.startAnimation(_Anim);
}

private void snackbarOutAnim(final Snackbar pSnackbar, final View pView) {
Animation _Anim = AnimationUtils.loadAnimation(pView.getContext(),
R.anim.snackbar_out_anim);
_Anim.setInterpolator(new FastOutSlowInInterpolator());
_Anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
pView.setVisibility(View.GONE);
pSnackbar.dismiss();
}
@Override
public void onAnimationStart(Animation animation) {}

@Override
public void onAnimationRepeat(Animation animation) {}
});
pView.startAnimation(_Anim);
}
Snackbar _Snackbar = Snackbar.make(view, "我是从左到右的Snackbar!", Snackbar.LENGTH_INDEFINITE);
_Snackbar.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View v) {

}
});
View _RootView = _Snackbar.getView();
snackbarInAnim(_Snackbar, _RootView);
TextView _Text = (TextView) _Snackbar.getView().findViewById(R.id.snackbar_text);
Button _Action = (Button) _Snackbar.getView().findViewById(R.id.snackbar_action);
_RootView.setBackgroundColor(ColorStateList.valueOf(0xFF99CCFF).getDefaultColor());
_Text.setTextColor(ColorStateList.valueOf(0xFFFFFFFF));
_Action.setTextColor(ColorStateList.valueOf(0xFFFFFF66));
_Snackbar.show();



其他动画效果就靠自己发挥啦。

六、后记
我把design包升级到25.1.0,发现源码有些地方改了,
Snackbar向上抽取出BaseTransientBottomBar类,以前在Snackbar里的一些操作放到BaseTransientBottomBar完成。
public final class Snackbar extends BaseTransientBottomBar<Snackbar>
SnackbarLayout向上抽取出BaseTransientBottomBar.SnackbarBaseLayout类,以前在SnackbarLayout里的操作都在SnackbarBaseLayout中完成。
public static final class SnackbarLayout extends BaseTransientBottomBar.SnackbarBaseLayout {
public SnackbarLayout(Context context) {
super(context);
}

public SnackbarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
显示和隐藏的回调之前的setCallback()过时,换成addCallback(@NonNull BaseCallback<B> callback),用的时候实现BaseCallback就好了,此外还增加了removeCallback()方法,用来移除回调的。
design_layout_snackbar_include.xml布局的TextView和Button外面是用SnackbarContentLayout包裹的,
<view
xmlns:android="http://schemas.android.com/apk/res/android"
class="android.support.design.internal.SnackbarContentLayout"
android:theme="@style/ThemeOverlay.AppCompat.Dark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<TextView
.../>
<Button
.../>
</view>

其他的基本上都一样的。

源码地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: