长沙建网站设计公司,甘肃新闻,信息设计网站,广州设计公司网站1.Snackbar
Snackbar是Material Design中的一个控件#xff0c;用来代替Toast。Snackbar是一个类似Toast的快速弹出消息提示的控件。Snackbar在显示上比Toast丰富#xff0c;而且提供了用户交互的接口。
①默认情况下#xff0c;Snackbar显示在屏幕底部#xff0c;它出现…1.Snackbar
Snackbar是Material Design中的一个控件用来代替Toast。Snackbar是一个类似Toast的快速弹出消息提示的控件。Snackbar在显示上比Toast丰富而且提供了用户交互的接口。
①默认情况下Snackbar显示在屏幕底部它出现在屏幕所有元素之上且同时最多只能显示一个Snackbar。
②Snackbar与某些视图相关联并且仅当视图在屏幕上时才会显示Snackbar。
③Snackbar出现时不会阻碍用户在屏幕上的输入。Snackbar可以自定义时长。
④当Snackbar在CoordinatorLayout下使用时支持右滑删除功能。 2.Snackbar的用法
Snackbar的用法很简单不需要在xml中写布局像Toast一样直接在代码里使用即可。
首先需要添加依赖
implementation com.google.android.material:$latest_version
然后就可以在代码中使用了
①最基本的用法
Snackbar.make(view, Show some message here,Snackbar.LENGTH_LONG)
.setAction(Action, v1 - { Log.e(TAG, 点击了确定按钮);
}).show(); 注意Snackbar不支持设置多个action如果设置多个action只有最后一个生效。
②设置颜色
Snackbar.make(view, Show some message here, Snackbar.LENGTH_SHORT)
.setBackgroundTint(ContextCompat.getColor(this, R.color.baseCyan))
.setActionTextColor(ContextCompat.getColor(this, R.color.white))
.setTextColor(ContextCompat.getColor(this,R.color.black))
.setAction(Action) { Log.e(TAG, 点击了确定按钮);
}
.show() ③添加回调
addCallback()用于给snackbar添加回调回调Snackbar弹出和关闭动作。
Snackbar.make(view, Show some message here, Snackbar.LENGTH_SHORT)
.addCallback(new Snackbar.Callback() { public void onShown(Snackbar sb) { super.onShown(sb) Log.d(TAG, onShown) } public void onDismissed( transientBottomBar: Snackbar?, event: Int) { super.onDismissed(transientBottomBar, event) Log.d(TAG, onDismissed) }
}).show();
④在文本前面添加图片
Snackbar snackbar Snackbar.make(view, 这是一个snackbar, Snackbar.LENGTH_SHORT);
snackbar.setAction(取消, new View.OnClickListener() { Override public void onClick(View v) { }
});
TextView textView snackbar.getView().findV iewById(R.id.snackbar_text);
Drawable drawable getResources().getDrawa ble(R.mipmap.ic_launcher_round);
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
textView.setCompoundDrawables(drawable, null, null, null);
//增加文字和图标的距离
textView.setCompoundDrawablePadding(20);
textView.setGravity(Gravity.CENTER);
snackbar.show(); ⑤自定义布局
自定义布局的步骤
1通过Snackbar.getView获取到view
1通过LayoutInflater去加载布局得到自定义的布局view
3通过①中获取到的view添加②中加载好的布局view
4通过①中得到的自定义布局获取里面的控件去执行一些操作比如点击事件设置文字和文字颜色等。
View rootView getWindow().getDecorView();
View coordinatorLayout rootView.findViewById(android.R.id.content);
Snackbar snackbar Snackbar.make( coordinatorLayout, , Snackbar.LENGTH_SHORT);
// 获取到Snackbar.getView获取的Snackbar的view
Snackbar.SnackbarLayout snackbarView (Snackbar.SnackbarLayout) snackbar.getView();
// 加载自定义布局
View inflate LayoutInflater.from( snackbar.getView().getContext()).inflate(R.layout.snacbar_layout, null);
// 获取自定义布局中的控件
TextView text inflate.findViewById( R.id.textView);
text.setText(自定义布局的Snackbar);
ImageView imageView inflate.findViewById( R.id.imageView);
imageView.setOnClickListener(v1 - Log.d(TAG, 点击了自定义布局中的控件));
// 将自定义布局view添加到SnackbarView中
snackbarView.addView(inflate);
snackbar.show();
⑥修改Snackbar的位置
自定义位置的步骤
1获取到SnackbarView的LayoutParams
2通过①中获取到的LayoutParams创建新的LayoutParams
③给②中的LayoutParams设置Gravity
④将新的LayoutParams设置给SnackbarView。
View rootView getWindow().getDecorView();
View coordinatorLayout rootView.findViewById(android.R.id.content);
Snackbar snackbar Snackbar.make(coordinatorLayout, , Snackbar.LENGTH_SHORT);
// 设置SnackbarView的padding都为0避免上图中出现黑色边框背景的情况
snackbar.getView().setPadding(0,0,0,0);
// 将SnackbarView的背景颜色设置为透明避免在自定义布局中有圆角或者自适应宽度的时候显示一块黑色背景的情况
snackbar.getView().setBackgroundColor(Color.TRANSPARENT);
// 获取到Snackbar.getView获取的Snackbar的view
Snackbar.SnackbarLayout snackbarView (Snackbar.SnackbarLayout) snackbar.getView();
// 获取到SnackbarView的LayoutParams
ViewGroup.LayoutParams layoutParams snackbarView.getLayoutParams();
// 新建一个LayoutParams将SnackbarView的LayoutParams的宽高传入
FrameLayout.LayoutParams fl new FrameLayout.LayoutParams(layoutParams.width, layoutParams.height);
// 设置新的元素位置
fl.gravity Gravity.CENTER;
// 将新的LayoutParams设置给SnackbarView
snackbarView.setLayoutParams(fl);
// 自定义的布局
View inflate LayoutInflater.from( snackbar.getView().getContext()).inflate(R.layout.snacbar_layout, null);
TextView text inflate.findViewById( R.id.textView);
text.setText(自定义布局的Snackbar);
ImageView imageView inflate.findViewById(R.id.imageView);
imageView.setOnClickListener(v1 - Log.d(TAG, 点击了自定义布局中的控件));
snackbarView.addView(inflate);
snackbar.show(); 3.Snackbar源码
①Snackbar使用静态方法make()创建实例
public static Snackbar make(View view, int resId, int duration) { return make(view, view.getResources().getText(resId), duration);
}
public static Snackbar make(View view, CharSequence text, int duration) { ViewGroup parent findSuitableParent( view); if (parent null) { throw new IllegalArgumentException(No suitable parent found from the given view. Please provide a valid view.); } final LayoutInflater inflater LayoutInflater.from(parent.getContext()); final SnackbarContentLayout content (SnackbarContentLayout) inflater.inflate( R.layout.design_layout_snackbar_include, parent, false); final Snackbar snackbar new Snackbar( parent, content, content); snackbar.setText(text); snackbar.setDuration(duration); return snackbar;
}
②findSuitableParent()
创建Snackbar实例需要寻找合适的父视图优先选择CoordinatorLayout作为父视图。
private static ViewGroup findSuitableParent( View view) { ViewGroup fallback null; do { if (view instanceof CoordinatorLayout) { return (ViewGroup) view; } else if (view instanceof FrameLayout) { if(view.getId() android.R.id.content) { return (ViewGroup) view; } else { fallback (ViewGroup) view; } } if (view ! null) { final ViewParent parent view.getParent(); view parent instanceof View ? (View) parent : null; } } while (view ! null); return fallback;
}
③SnackbarContentLayout
SnackbarContentLayout继承LinearLayout并实现了BaseTransientBottomBar.ContentViewC allback包含一个TextView和Button。
design_layout_snackbar_include.xml文件
view xmlns:androidhttp://schemas.andro id.com/apk/res/android classandroid.support.design.internal.Sna ckbarContentLayout android:themestyle/ThemeOverlay.Ap pCompat.Dark android:layout_widthmatch_parent android:layout_heightwrap_content android:layout_gravitybottom TextView android:idid/snackbar_text android:layout_widthwrap_content android:layout_heightwrap_content android:layout_weight1 android:paddingTopdimen/design_sn ackbar_padding_vertical android:paddingBottomdimen/desig n_snackbar_padding_vertical android:paddingLeftdimen/design_sn ackbar_padding_horizontal android:paddingRightdimen/design_s nackbar_padding_horizontal android:textAppearancestyle/TextAp pearance.Design.Snackbar.Message android:maxLinesinteger/design_sna ckbar_text_max_lines android:layout_gravitycenter_vertical| left|start android:ellipsizeend android:textAlignmentviewStart/ Button android:idid/snackbar_action android:layout_widthwrap_content android:layout_heightwrap_content android:layout_marginLeftdimen/de sign_snackbar_extra_spacing_horizontal android:layout_marginStartdimen/de sign_snackbar_extra_spacing_horizontal android:layout_gravitycenter_vertical| right|end android:minWidth48dp android:visibilitygone android:textColor?attr/colorAccent style?attr/borderlessButtonStyle/
/view
④SnackbarManager类
SnackbarManager用来管理Snackbar控件的状态。
Snackbar的show()方法会调用SnackbarManager的show(int, Callback)方法而mManagerCallback会回调Snackbar的showView()和hideView(int)方法。
static { sHandler new Handler( Looper.getMainLooper(), new Handler.Callback() { Override public boolean handleMessage(Message message) { switch (message.what) { case MSG_SHOW: ((BaseTransientBottomBar) message.obj).showView(); return true; case MSG_DISMISS: ((BaseTransientBottomBar) message.obj).hideView(message.arg1); return true; } return false; } });
}
final SnackbarManager.Callback mManagerCallback new SnackbarManager.Callback() { Override public void show() { sHandler.sendMessage( sHandler.obtainMessage(MSG_SHOW, BaseTransientBottomBar.this)); } Override public void dismiss(int event) { sHandler.sendMessage( sHandler.obtainMessage(MSG_DISMISS, event, 0, BaseTransientBottomBar.this)); }
};
public void show() { SnackbarManager.getInstance().show( mDuration, mManagerCallback);
}
SnackbarManager内部包含两个记录mCurrentSnackbar和mNextSnackbar。在SnackbarManager的show(int, Callback)方法中①查看是否是当前Snackbar如果是更新超时时间结束。②查看是否是NextSnackbar如果是更新数据如果不是创建新的NextSnackbar。③取消当前Snackbar或者显示NextSnackbar。
⑤show(int, Callback)方法
public void show(int duration, Callback callback) { synchronized (mLock) { if (isCurrentSnackbarLocked(callback)) { // 如果是当前Snackbar更新duration和超时提示 mCurrentSnackbar.duration duration; mHandler.removeCallbacksAndMessag es( mCurrentSnackbar); scheduleTimeoutLocked( mCurrentSnackbar); return; } else if (isNextSnackbarLocked(callback)){ // 如果是NextSnackbar更新duration mNextSnackbar.duration duration; } else { // 否则就创建新的NextSnackbar mNextSnackbar new SnackbarRecord(duration, callback); } if (mCurrentSnackbar ! null cancelSnackbarLocked(mCurrentSnackbar, Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE)) { // 如果当前Snackbar存在取消显示当前Snackbar return; } else { mCurrentSnackbar null; // 如果当前Snackbar不存在显示NextSnackbar showNextSnackbarLocked(); } }
}
// 取消显示当前Snackbar调用callback的dismiss(DISMISS_EVENT_CONSECUTIVE)方法
private boolean cancelSnackbarLocked( SnackbarRecord record, int event) { final Callback callback record.callback.get(); if (callback ! null) { mHandler.removeCallbacksAndMessages( record); callback.dismiss(event); return true; } return false;
}
private boolean isCurrentSnackbarLocked( Callback callback) { return mCurrentSnackbar ! null mCurrentSnackbar.isSnackbar(callback);
}
private boolean isNextSnackbarLocked( Callback callback) { return mNextSnackbar ! null mNextSnackbar.isSnackbar(callback);
}
// 更新超时提示
private void scheduleTimeoutLocked( SnackbarRecord r) { if (r.duration Snackbar.LENGTH_INDEFINITE) { return; } int durationMs LONG_DURATION_MS; if (r.duration 0) { durationMs r.duration; } else if (r.duration Snackbar.LENGTH_SHORT) { durationMs SHORT_DURATION_MS; } mHandler.removeCallbacksAndMessages(r); mHandler.sendMessageDelayed( Message.obtain(mHandler, MSG_TIMEOUT, r), durationMs);
}
// 显示NextSnackbar调用callback的show方法
private void showNextSnackbarLocked() { if (mNextSnackbar ! null) { mCurrentSnackbar mNextSnackbar; mNextSnackbar null; final Callback callback mCurrentSnackbar.callback.get(); if (callback ! null) { callback.show(); } else { mCurrentSnackbar null; } }
}
Snackbar的showView()会调用onViewShown()hideView(int)会调用onViewHidden(int)
final void showView() { ... ... if (shouldAnimate()) { // If animations are enabled, animate it in animateViewIn(); } else { // Else if anims are disabled just call back now onViewShown(); } ... ...
}
final void hideView(final int event) { if (shouldAnimate() mView.getVisibility() View.VISIBLE) { animateViewOut(event); } else { // If anims are disabled or the view isnt visible, just call back now onViewHidden(event); }
}
void onViewShown() { SnackbarManager.getInstance().onShown( mManagerCallback);
}
void onViewHidden(int event) { SnackbarManager.getInstance().onDismi ssed(mManagerCallback);
}
SnackbarManager的onShown(Callback)和onDismissed(Callback)方法
public void onShown(Callback callback) { synchronized (mLock) { if (isCurrentSnackbarLocked(callback)) { scheduleTimeoutLocked( mCurrentSnackbar); } }
}
public void onDismissed(Callback callback) { synchronized (mLock) { if (isCurrentSnackbarLocked(callback)) { // If the callback is from a Snackbar currently show, remove it and show a new one mCurrentSnackbar null; if (mNextSnackbar ! null) { showNextSnackbarLocked(); } } }
}