giphy的副本.gif
博客讲解demo地址:https://github.com/18380438200/MDView
ToolBar(因为涉及到,也一并讲解)
从Android3.0后出现ActionBar,但是这效果,谁用谁知道啊。颜色不好看不说,布局也是无法订制,都不如自定义ActionBar的好。可见我的另一篇自定义[Actionbar] http://www.jianshu.com/p/43b51e1062f1。
使用方式:
1.首先在Activity主题里面将默认Actionbar改为NoActionbar
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
2.绑定toolbar ,setSupportActionBar(toolbar) 设置toolbar为标题栏
3.设置常用属性:
toolbar.setNavigationIcon(int resId); toolbar.setLogo(int resId); toolbar.setTitle(""); toolbar.setSubtitle(""); toolbar.setOnMenuItemClickListener(Toolbar.OnMenuItemClickListener listener);
4.引用菜单
@Override public boolean onCreateOptionsMenu(Menu menu) { //引入options菜单 getMenuInflater().inflate(R.menu.menu,menu); return true; }
5.在menu文件夹中设置菜单
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu_1" android:title="菜单1" android:icon="@mipmap/make_music_voice_changer_female" app:showAsAction="collapseActionView"/> <item android:id="@+id/menu_2" android:title="菜单2" android:icon="@mipmap/make_music_voice_changer_female" app:showAsAction="collapseActionView"/> <item android:id="@+id/menu_3" android:title="菜单3" android:icon="@mipmap/make_music_voice_changer_female" app:showAsAction="collapseActionView"/> <item android:id="@+id/menu_4" android:title="菜单4" android:icon="@mipmap/make_music_voice_changer_female" app:showAsAction="collapseActionView"/></menu>
或者直接在布局中添加子view使用
<android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" > <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="返回" android:textSize="13sp" android:textColor="@android:color/white" /> <TextView android:id="@+id/tv2" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="right" android:layout_centerHorizontal="true" android:layout_marginRight="6dp" android:gravity="center" android:padding="4dp" android:textColor="#fff" android:textSize="14sp" android:text="菜单"/> </android.support.v7.widget.Toolbar>
showAsAction属性
ifRoom 会显示在Item中,空间不足会将后面item收起来,如果已经有4个或者4个以上的Item时会隐藏在溢出列表中。
never 永远不会显示。只会在藏出列表中显示,而且只显示标题,所以在定义item的时候,最好把标题都带上。
always 无论是否超出空间,总会显示。
withText withText值示意Action bar要显示文本标题。Action bar会尽可能的显示这个标题,但是,如果图标有效并且受到Action bar空间的限制,文本标题有可能显示不全。
collapseActionView 声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开。否则,这个操作视窗在默认的情况下是可见的,并且即便在用于不适用的时候,也要占据操作栏的有效空间。
例如效果:ifroom的效果
collapseActionView的效果
Coordinatorlayout :
定义:is a super-powered Framelayout
是一个超级有力量的爸爸,官方给的定义就足以证明它的强大。
作用:协调子view的相互关系,比如位置、大小,就像有几个调皮孩子的爸爸,要管管孩子的行为。
Behavior:
Behavior的来源
打开Coordinatorlayout看,Behavior是CoordinatorLayout的一个泛型抽象内部类(这么长累不累呀),所以给子view添加layout_behavior属性是来自于它。
我写了一个例子来理解CoordinatorLayout的工作原理:
这是一个大叔跟随女孩的故事
<android.support.design.widget.CoordinatorLayout xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/coordinatorLayout" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context="com.example.md.mdview.CoordinatorLayoutActivity"> <View android:id="@+id/view_girl" android:layout_width="70dp" android:layout_height="70dp" android:layout_marginLeft="200dp" android:background="@mipmap/make_music_voice_changer_female" /> <View android:id="@+id/view_uncle" android:layout_width="100dp" android:layout_height="100dp" android:background="@mipmap/make_music_voice_changer_uncle" app:layout_behavior="com.example.md.mdview.RunBehavior"/></android.support.design.widget.CoordinatorLayout>
布局:两个子view,操作viewgirl,viewuncle也会相应跟着走,这就要写一个联动关系,用自定义Behavior实现
public class RunBehavior extends CoordinatorLayout.Behavior<View>{ public RunBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) { int top = dependency.getTop(); int left = dependency.getLeft(); ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) child.getLayoutParams(); params.topMargin = top - 400; params.leftMargin = left; child.setLayoutParams(params); return true; } @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return true; } }
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) 方法:
根据条件过滤判断返回值,返回true联动,返回flase不联动,即behavior不生效
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency)
当 dependency这个哥哥发生变化时, 另一个child弟弟也要跟着去玩
一个view根据另一个view的变化而变化, dependency被 child监听
功能是child的y值永远比dependency大400像素(废话,还用说吗)
app:layout_behavior="com.example.md.mdview.RunBehavior"
这里一定要写上带参数的构造方法,因为coordinatorlayout是根据反射(所以是包名.类名路径)获取这个behavior,是从这个构造方法获得对象的,否则会报
image.png
@Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: params.leftMargin = (int) (event.getX() - viewGirl.getMeasuredWidth() / 2); params.topMargin = (int) (event.getY() - viewGirl.getMeasuredHeight() / 2); viewGirl.setLayoutParams(params); break; case MotionEvent.ACTION_MOVE: params.leftMargin = (int) (event.getX() - viewGirl.getMeasuredWidth() / 2); params.topMargin = (int) (event.getY() - viewGirl.getMeasuredHeight() / 2); viewGirl.setLayoutParams(params); break; } return true; }
最后是在界面监听手指的位置,给viewGirl设置手指的位置,viewgril变化了,viewuncle也就随之变化了。
好,在会了Coordinatorlayout的用法,最外层父布局有了,该添加两个子view了。这里里面分别加入AppbarLayout和NestedScrollView作子view,给NestedScrollView加上behavior,就可以让AppbarLayout跟随NestedScrollView的Behavior联动。Android已经自带了app:layout_behavior="@string/appbar_scrolling_view_behavior",只要滚动发生,就会给自己的子view(if
instance of Appbarlayout)添加滚动事件。不明白这俩控件紧接着看后面讲解。
当前布局变为:
<android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="50dp" android:background="#0e932e" app:layout_collapseMode="pin"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" android:textColor="#000" android:padding="10dp" android:text=""/> </android.support.v4.widget.NestedScrollView></android.support.design.widget.CoordinatorLayout>
NestedScrollView (viewgirl的角色)
NestedScrolling机制能够让父View和子View在滚动式进行配合,其基本流程如下:
当子view开始滚动之前,可以通知父View,让其先于自己进行滚动;
子View自己进行滚动;子view滚动之后,还可以通知父view继续滚动。
而要实现这样的交互机制,首先父view要实现NestedScrollingParent接口,而子View需要实现NestedScrollingChild接口,在这套机制中子View是发起者,父view是接受回调并做出响应的。
以下是几个关键的类和接口
/** * NestedScrollView is just like {@link android.widget.ScrollView}, but it supports acting * as both a nested scrolling parent and child on both new and old versions of Android. * Nested scrolling is enabled by default. */public class NestedScrollView extends FrameLayout implements NestedScrollingParent, NestedScrollingChild, ScrollingView { static final int ANIMATED_SCROLL_GAP = 250; static final float MAX_SCROLL_FACTOR = 0.5f; private static final String TAG = "NestedScrollView"; /** * Interface definition for a callback to be invoked when the scroll * X or Y positions of a view change. * * <p>This version of the interface works on all versions of Android, back to API v4.</p> * * @see #setOnScrollChangeListener(OnScrollChangeListener) */ public interface OnScrollChangeListener { /** * Called when the scroll position of a view changes. * * @param v The view whose scroll position has changed. * @param scrollX Current horizontal scroll origin. * @param scrollY Current vertical scroll origin. * @param oldScrollX Previous horizontal scroll origin. * @param oldScrollY Previous vertical scroll origin. */ void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); } private long mLastScroll; private final Rect mTempRect = new Rect(); private OverScroller mScroller; private EdgeEffect mEdgeGlowTop; private EdgeEffect mEdgeGlowBottom; ······
作者:奔跑吧李博
链接:https://www.jianshu.com/p/cd93da2b7a24