Android 5.0 Lollipop版本加入了Material Design库,通过这个库,开发人员可以轻松实现体现了Material Design风格的界面开发。本文将通过示例讲解该库里面常用的一些控件的使用方法,包括:
TextInputLayout,FloatingActionButton,Snackbar,CoordinatorLayout等。
TextInputLayout
通过将传统的Edittext用TextInputLayout包裹起来,可以使得在用户输入的时候hint信息悬浮在输入框上方,随时提醒用户当前输入的内容是什么,效果如下图:
使用很简单:
<android.support.design.widget.TextInputLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<EditText
android:layout_width="200dp"
android:layout_height="wrap_content"
android:hint="Input your name here"/>
</android.support.design.widget.TextInputLayout>
其hint颜色,下划线默认颜色,高亮颜色,悬浮hint颜色等都可以设置,具体设置在res/values/styles.xml中,在当前app使用的Theme里设置:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/blue</item>
<item name="android:textColorHint">@color/gray</item>
<item name="colorControlNormal">@color/black</item>
<item name="colorControlActivated">@color/yellow</item>
<item name="colorControlHighlight">@color/green</item>
</style>
</resources>
其中textColorHint代表hint的颜色,colorControlNormal代表下划线没有获取焦点的颜色,colorControlActivated/colorControlHighlight代表了获取焦点或者点击的时候下划线的颜色。其他各种名称和代表的color如下图所示:
FloatingActionButton是界面上的一个悬浮按钮,用来指示界面上的某个操作,界面下所示。
可以通过anchor指定以哪个控件为基准,并用anchorGravity属性指定和基准控件的对齐方式,来将它放在界面上的某个位置。
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
app:layout_anchor="@id/collapsing_toolbar_layout"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@android:drawable/ic_dialog_email" />
添加响应事件:
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
}
snackbar
Snackbar是类似于toast的提醒类型的消息,展示在界面底部,可以滑动删除。除了展示文字提示外,还可以添加一个action进行一些操作。
Snackbar.make(view, "这里是展示的文字", Snackbar.LENGTH_SHORT)
.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View view) {
// do something
}
).show();
CoordinatorLayout
CoordinatorLayout继承自ViewGroup,是一个加强版的FrameLayout。它有两个主要作用:
- 提供了一种实现MaterialDesign样式的简单布局
- 在该布局内的元素可以实现UI交互
利用CoordinatorLayout可以实现类似知乎的ToolBar随页面滑动而隐藏或展示,以及ToolBar折叠的效果。
ToolBar隐藏效果
使用下面的xml实现上面Toolbar随RecyclerView滑动而隐藏或展示的效果。
<android.support.design.widget.CoordinatorLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="parallax"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
...
</android.support.design.widget.CoordinatorLayout>
这里有三个要点:
- 将Toolbar包裹在AppBarLayout里,CoordinatorLayout作为最外层layout。
- 指定Toolbar的layout_scrollFlags属性为"scroll | enterAlways"
- 同时给RecyclerView指定behavior属性为系统内置的“appbar_scrolling_view_behavior”
这样就能实现CoordinatorLayout里面组件互相配合的效果。
Toolbar折叠效果
使用下面的xml实现Toolbar折叠效果:
<android.support.design.widget.CoordinatorLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="192dp"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:background="@drawable/girl">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="parallax" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
...
</android.support.design.widget.CoordinatorLayout>
相比于Toolbar隐藏效果,折叠效果的实现有以下几个要点:
- 需要在Toolbar外面先包裹一层CollapsingToolbarLayout,然后在被AppBarLayout包裹
- 给CollapsingToolbarLayout设置layout_scrollFlags属性为"scroll | exitUntilCollapsed"
- 指定Toolbar的layout_collapseMode属性为"parallax"
FooterView的隐藏和展示效果
下面是FooterView隐藏和展示效果,向上滑动RecyclerView时评论布局隐藏,下滑时展示。
评论部分的布局如下:
<LinearLayout
android:id="@+id/footer_layout"
android:layout_width="match_parent"
android:layout_height="60dp"
app:layout_anchor="@id/recycler_view"
app:layout_anchorGravity="bottom"
android:background="@color/yellow"
app:layout_behavior=".FooterBehavior"
android:visibility="gone"
tools:visibility="visible">
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="添加评论"
android:layout_margin="10dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发布评论"/>
</LinearLayout>
为了让FooterView响应RecyclerView滑动事件,我们指定layout的layout_behavior属性值为FooterBehavior。它是我们自定义的一个Behavior,Behavior是一种CoordinatorLayout内部元素进行交互的方式,我们可以根据需要实现自己的Behavior,实现特定的交互效果。
public class FooterBehavior extends CoordinatorLayout.Behavior<View> {
private boolean visible = false;
public FooterBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof RecyclerView;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
return true;
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return true;
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
if (dyConsumed > 0 || dyUnconsumed > 0) {
moveOupAnimation(child);
}
}
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) {
if (velocityY < -0.5) {
moveInAnimation(child);
} else {
moveOupAnimation(child);
}
return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
}
...
}
这里有几个要点:
- 要重写Behavior(context, attrs)这个构造函数,否则通过反射调用Behavior时会出错
- 重写layoutDependsOn函数,指定当前view所依赖的view,这里可以是依赖某种类型的view,如代码中所示依赖RecyclerView;也可以是依赖某一个特定的View,根据view的id进行判断
- 根据自己的实际需求,在所依赖的RecyclerView的onStartNestedScroll事件和onNestedFling中,加入对view本身的处理
这里实现FooterView的动画效果代码如下,关于动画的实现技术可以参考我的这篇文章:
private void moveInAnimation(View v) {
if (!visible) {
v.setVisibility(View.VISIBLE);
ObjectAnimator moveTopAnim = ObjectAnimator.ofFloat(v, "translationY", v.getHeight(), 0);
moveTopAnim.setDuration(300);
moveTopAnim.start();
visible = true;
}
}
private void moveOupAnimation(View v) {
if (visible) {
ObjectAnimator moveTopAnim = ObjectAnimator.ofFloat(v, "translationY", 0, v.getHeight());
moveTopAnim.setDuration(300);
moveTopAnim.start();
visible = false;
}
}
参考:
https://android-developers.googleblog.com/2015/05/android-design-support-library.html