ScrollView滑动监听实现界面动画效果
来源:互联网 发布:python统计字母个数 编辑:程序博客网 时间:2024/05/01 19:35
Andriod进阶知识之一,滑动监听也是初学者不得不学习的一项技能。关于滑动,你能想到什么?ScrollView、ListView、GridView、WebView、RecyclerView。。。你是否写过或研究过ScrollView滑动监听的代码呢?其他控件的滑动监听代码是怎么实现的呢?看看下面的效果,是不是很想实现?让我们带着这些疑问,一起进入Android滑动监听的世界吧。
一、ScrollView滑动监听,实现ActionBar显示和隐藏
1、写一个ScrollView滑动监听的接口,供实现滑动监听的Activity实现,代码如下:
public interface ObservableScrollViewCallbacks { /** * 滑动过程监听 * @param scrollY 当前滑动位置 * @param firstScoll 是否第一次滑动 * @param dragging 是否滑动中 */ void onScrollChanged(int scrollY, boolean firstScoll, boolean dragging); //当按下事件发生时候调用此方法 void onDownMotionEvent(); //滑动的状态 void onUpOrCancleMotionEvent(ScrollState scrollState);}
滑动状态用Enum枚举类型表示,STOP表示滑动停止,UP表示向上滑动,DOWN表示向下滑动,代码如下:
public enum ScrollState { STOP, UP, DOWN,}
2、写一个Scrollable接口,供自定义ScrollView控件ObservableScrollView实现,代码如下:
public interface Scrollable { //接口设置 void setScrollViewCallbacks(ObservableScrollViewCallbacks listener); //获取Y轴滑动距离 int getCurrentScrollY(); //设置手势拦截 void setTouchInterceptionViewGroup(ViewGroup viewGroup);}
3、自定义ObservableScrollView,实现Scrollable接口,代码如下:
public class ObservableScrollView extends ScrollView implements Scrollable{ private int mPrevScrollY; private int mScrollY; private ScrollState mScrollState; private boolean mFirstScroll,mDraggging; private ObservableScrollViewCallbacks callbacks; public ObservableScrollView(Context context) { super(context); } public ObservableScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public ObservableScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); mScrollY = t; if (callbacks != null) { callbacks.onScrollChanged(t, mFirstScroll, mDraggging); } if (mFirstScroll) { mFirstScroll = false; } Log.i("ObservableScrollview",mPrevScrollY +" "+ t); if(mPrevScrollY < t){ mScrollState = ScrollState.UP; }else { mScrollState = ScrollState.DOWN; } mPrevScrollY = t; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getActionMasked()){ case MotionEvent.ACTION_DOWN: mFirstScroll = mDraggging = true; break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mDraggging = false; callbacks.onUpOrCancleMotionEvent(mScrollState); break; case MotionEvent.ACTION_MOVE: break; } return super.onTouchEvent(ev); } @Override public void setScrollViewCallbacks(ObservableScrollViewCallbacks listener) { callbacks = listener; } @Override public int getCurrentScrollY() { return mScrollY; } @Override public void setTouchInterceptionViewGroup(ViewGroup viewGroup) { }}这里有必要解释下onScrollChanged方法中的四个参数,l , t分别表示触摸点距离View左上角的距离,oldl , oldt分别表示上一次触摸点距离View左上角的距离。
这里判断滑动方向是根据当前触摸点的Y轴位置(距离View顶部的距离)和之前触摸点的Y轴位置判断的,如果当前触摸点的位置距离View顶部的距离大于之前触摸点距离View顶部的距离,表示向上滑动,反之,向下滑动。每次滑动后,记得把当前触摸点距离View顶部的距离赋值给之前触摸点距离View顶部的临时变量。
这里判断是否第一次滑动以及是否在滑动中赋值写在onInterceptTouchEvent方法中,是因为View的touch事件生命周期执行顺序是onInterceptTouchEvent-->onTouchEvent.关于View的事件拦截机制可以参考这篇博文 滑动事件拦截处理机制详解 写得很详细。手指抬起的时候,isDragging赋值false,同时调用接口的onUpOrCancleMotionEvent方法将滑动状态传入接口,供Activity回调。
4、写一个Activity实现ObserableScrollViewCallBacks接口,代码如下:
public class ActionBarControllScrollviewActivity extends AppCompatActivity implements ObservableScrollViewCallbacks{ @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_actionbarcontrolscrollview); ObservableScrollView scrollView = (ObservableScrollView) findViewById(R.id.scroll); scrollView.setScrollViewCallbacks(this); } @Override public void onScrollChanged(int scrollY, boolean firstScoll, boolean dragging) { } @Override public void onDownMotionEvent() { } @Override public void onUpOrCancleMotionEvent(ScrollState scrollState) { ActionBar actionBar = getSupportActionBar(); if(actionBar == null){ return; } if(scrollState == ScrollState.UP){ if(actionBar.isShowing()){ actionBar.hide(); } }else if(scrollState == ScrollState.DOWN){ if(!actionBar.isShowing()){ actionBar.show(); } } }}
R.layout.actionbarcontrolscrollview代码如下:
<com.lc.proctice.androidstudioproctice.anim.widget.ObservableScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/scroll" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" android:layout_marginTop="16dp" android:text="@string/lipsum" /></com.lc.proctice.androidstudioproctice.anim.widget.ObservableScrollView>
注意,ObservableScrollView控件是自定义的,这里引入要根据自己项目的实际文件位置命名。
此事件只处理了ActionBar的显示和隐藏,根据滑动状态处理,向上滑动,则隐藏ActionBar,向下滑动,则显示ActionBar。这样,前面动图的滑动效果就实现啦。
二、ScrollView滑动监听,实现ToolBar(ActionBar)文字的缩放移动
效果图:
FlexibleSpaceActionBarScrollviewActivity代码如下:
public class FlexibleSpaceActionBarScrollviewActiivty extends AppCompatActivity implements ObservableScrollViewCallbacks { private View mFlexibleSpaceView; //滑动可变区域 private View mToolbarView; private TextView mTitleView; private int mFlexibleSpaceHeight; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_flexiblespacetoolbarscrollview); mFlexibleSpaceView = findViewById(R.id.flexible_space); mTitleView = (TextView) findViewById(R.id.title); mTitleView.setText(getTitle()); setTitle(null); mToolbarView = findViewById(R.id.toolbar); final ObservableScrollView scrollView = (ObservableScrollView) findViewById(R.id.scroll); scrollView.setScrollViewCallbacks(this); mFlexibleSpaceHeight = getResources().getDimensionPixelSize(R.dimen.flexible_space_height);//216 int flexibleSpaceAndToolbarHeight = mFlexibleSpaceHeight + getActionBarSize(); //216+168=384 Log.i("mFlexibleSpaceHeight:",mFlexibleSpaceHeight+" ActionBarSize:"+getActionBarSize()); findViewById(R.id.body).setPadding(0, flexibleSpaceAndToolbarHeight ,0 ,0); //初始化加载时给滑动可变区域设置一个高度 384 mFlexibleSpaceView.getLayoutParams().height = flexibleSpaceAndToolbarHeight; //给移动的文字设置滑动监听动画 ScrollUtils.addOnGlobalLayoutListener(mTitleView, new Runnable() { @Override public void run() { updateFlexibleSpaceText(scrollView.getCurrentScrollY()); } }); } @Override public void onScrollChanged(int scrollY, boolean firstScoll, boolean dragging) { updateFlexibleSpaceText(scrollY); } @Override public void onDownMotionEvent() { } @Override public void onUpOrCancleMotionEvent(ScrollState scrollState) { } //获取actionBarSize 返回168 protected int getActionBarSize(){ TypedValue typedValue = new TypedValue(); int[] textSizeAttr = new int[]{R.attr.actionBarSize}; TypedArray typedArray = this.obtainStyledAttributes(typedValue.data,textSizeAttr); int actionBarSize = typedArray.getDimensionPixelSize(0,-1); typedArray.recycle(); return actionBarSize; } private void updateFlexibleSpaceText(final int scrollY) { Log.i("scrollY滑动距离:",scrollY+" mFlexibleSpaceHeight高度:"+mFlexibleSpaceHeight ); //设置滑动区域的滑动距离 ViewHelper.setTranslationY(mFlexibleSpaceView, -scrollY); //设置滑动区域的滑动距离介于0-216 int adjustedScrollY = (int) ScrollUtils.getFloat(scrollY, 0, mFlexibleSpaceHeight); Log.i("scrollY滑动距离:","adjustedScrollY" + adjustedScrollY); //计算文字缩放的倍数值 float maxScale = (float) (mFlexibleSpaceHeight - mToolbarView.getHeight()) / mToolbarView.getHeight(); float scale = maxScale * ((float) mFlexibleSpaceHeight - adjustedScrollY) / mFlexibleSpaceHeight; //设置文字放大倍数 设置中心点位置为中间点 设置缩放比例 ViewHelper.setPivotX(mTitleView, 0); ViewHelper.setPivotY(mTitleView, 0); ViewHelper.setScaleX(mTitleView, 1 + scale); ViewHelper.setScaleY(mTitleView, 1 + scale); //设置文字移动位置 int maxTitleTranslationY = mToolbarView.getHeight() + mFlexibleSpaceHeight - (int) (mTitleView.getHeight() * (1 + scale)); int titleTranslationY = (int) (maxTitleTranslationY * ((float) mFlexibleSpaceHeight - adjustedScrollY) / mFlexibleSpaceHeight); ViewHelper.setTranslationY(mTitleView, titleTranslationY); }}
动画效果用nineoldandroids实现, android studio环境引入
compile 'com.nineoldandroids:library:2.4.0'
本例中用到的nineoldandroids的几个方法介绍:
ViewHelper.setTranslationY(view,distance); 将view在Y轴方向移动distance距离
ViewHelper.setPivotX(view,0);
ViewHelper.setPivoY(view,0); 将view的缩放中心放置在view的中间点
ViewHelper.setScaleX(view,scale); 设置view在X轴方向的缩放倍数
ViewHelper.setScaleY(view,scale); 设置view在Y轴方向的缩放倍数
示例代码中所有滑动距离都是用像素px表示。px和dp之间的转换如下:
R.layout.flexiblespacetoolbarscrollview 布局文件代码如下:<span style="white-space:pre"></span>/** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */public static int dip2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}/** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp */public static int px2dip(Context context, float pxValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.lc.proctice.androidstudioproctice.anim.widget.ObservableScrollView android:id="@+id/scroll" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:scrollbars="none"> <FrameLayout android:id="@+id/body" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="@dimen/flexible_space_height"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/white" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:text="@string/lipsum" /> </FrameLayout> </com.lc.proctice.androidstudioproctice.anim.widget.ObservableScrollView> <View android:id="@+id/flexible_space" android:layout_width="match_parent" android:layout_height="0dp" android:background="@color/primary" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:minHeight="?attr/actionBarSize" app:popupTheme="@style/Theme.AppCompat.Light.DarkActionBar" app:theme="@style/Base.Widget.AppCompat.Toolbar" /> <!-- android:layout_marginLeft on FrameLayout seems to be ignored on Android 2.3 so add a parent RelativeLayout and set padding to it. --> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="@dimen/toolbar_margin_start"> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" android:gravity="center_vertical" android:maxLines="1" android:minHeight="?attr/actionBarSize" android:textColor="@android:color/white" android:textSize="20sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <View android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@android:color/transparent" /> <View android:layout_width="match_parent" android:layout_height="@dimen/flexible_space_height" android:background="@android:color/transparent" /> </LinearLayout> </RelativeLayout></FrameLayout>
- ScrollView滑动监听实现界面动画效果
- ScrollView实现滑动效果
- scrollview+pagecontrol实现滑动界面
- 自定义ScrollView,实现ScrollView滑动监听并记录滑动位置。
- Android中实现监听ScrollView滑动事件
- ViewPager滑动动画效果实现
- ScrollView滑动悬停ToolBar效果实现
- 监听ScrollView滑动方向
- ScrollView滑动的监听
- ScrollView 滑动监听
- Android ScrollView滑动监听
- scrollview监听滑动位置
- ScrollView的滑动监听
- ScrollView的滑动监听
- ScrollView滑动监听
- 滑动scrollview时,随距离改变属性的动画原理!(类似陌陌,网易,path个人属性界面的动画效果)
- Android 监听ScrollView滑动 实现布局背景、文本颜色渐变
- 重写ScrollView 实现滑动监听(top栏透明度渐变)
- Android 中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()解析
- C++ 虚函数表解析
- Android JSSE实现SSL双向认证(阻塞模式及非阻塞模式)
- 防丢APP源码
- 程序员学习路线,如何进阶中高级程序员
- ScrollView滑动监听实现界面动画效果
- RxJava concat符操作处理多数据源
- Java 序列化Serializable详解(附详细例子)
- 基本算法之一——直接插入排序
- 怎么用maven创建一个Java Web项目?
- PHP 浏览器禁用cookie,解决session变量不能传值
- TabHost
- Scroller的使用,让View随心所欲的移动
- HTML5多媒体audio和video(一)