Android_Scroller滑动动画

来源:互联网 发布:garageband软件下载 编辑:程序博客网 时间:2024/06/06 14:11

转载请注明出处:http://blog.csdn.net/y22222ly/article/details/51842218

当我们在使用view的scrollTo()或scrollBy()时,会发现这个滑动很生硬,没有动画效果,一下就过去了,就像我前篇文章提到的那样。如果能平滑的滑动回去的话,最好不过了,刚好安卓提供一个Scroller类,专门来处理view在scrollTo()或scrollBy()时没有滑动效果的问题。

Scroller基本使用

下例源码引用自:http://ipjmc.iteye.com/blog/1615828
该大神详细说明了各个方法的用法。

import android.content.Context;  import android.util.AttributeSet;  import android.util.Log;  import android.view.View;  import android.widget.LinearLayout;  import android.widget.Scroller;  public class CustomView extends LinearLayout {      private static final String TAG = "Scroller";      private Scroller mScroller;      public CustomView(Context context, AttributeSet attrs) {          super(context, attrs);          mScroller = new Scroller(context);      }      //调用此方法滚动到目标位置      public void smoothScrollTo(int fx, int fy) {          int dx = fx - mScroller.getFinalX();          int dy = fy - mScroller.getFinalY();          smoothScrollBy(dx, dy);      }      //调用此方法设置滚动的相对偏移      public void smoothScrollBy(int dx, int dy) {          //设置mScroller的滚动偏移量          mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);          invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果      }      @Override      public void computeScroll() {          //先判断mScroller滚动是否完成          if (mScroller.computeScrollOffset()) {              //这里调用View的scrollTo()完成实际的滚动              scrollTo(mScroller.getCurrX(), mScroller.getCurrY());              //必须调用该方法,否则不一定能看到滚动效果              postInvalidate();          }          super.computeScroll();      }  } 

使用Scroller分三步:
1. 声明与初始化
2. 调用startScroll()一定要注意4个参数,前2个为当前滑动偏移量,后2个为需要滑动的偏移量
3. 重写view的computeScroll()方法,调用mScroller.computeScrollOffset()计算滑动值
4. 使用计算后的Scroller实例,调用view的scrollTo()进行滑动

Scroller实战

根据上述代码后自己学习后,对前一篇文章提到的滑动处理scrollTo()问题做了实现。
效果图:
这里写图片描述
源码:

package com.example.y2222.myview;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.animation.LinearInterpolator;import android.widget.LinearLayout;import android.widget.Scroller;import com.example.y2222.myapplication.R;/** * Created by raise.yang on 2016/06/29. */public class GestureDemoView extends LinearLayout {    //1,定义GestureDetector类    private GestureDetector m_gestureDetector;    //1,定义Scroller类    private Scroller m_scroller;    private int m_max_scrollX;    public GestureDemoView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public GestureDemoView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //设置为可点击        setClickable(true);        //2,初始化手势类,同时设置手势监听        m_gestureDetector = new GestureDetector(context, onGestureListener);        LayoutInflater.from(context).inflate(R.layout.view_gesture, this);        // 2,初始化Scroller类,可自定义插值器        m_scroller = new Scroller(getContext(), new LinearInterpolator());    }    @Override    public boolean onTouchEvent(MotionEvent event) {        //3,将touch事件交给gesture处理        m_gestureDetector.onTouchEvent(event);        if (event.getAction() == MotionEvent.ACTION_UP) {            // GestureDetector没有处理up事件的方法,只能在这里处理了。            int scrollX = getScrollX();            if (scrollX > m_max_scrollX / 2) {                show_right_view();            } else {                hide_right_view();            }        }        return super.onTouchEvent(event);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            //测量子view的宽高,?不测量,右侧布局会不显示,这里有点疑问            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);            if (i == 1) {                m_max_scrollX = getChildAt(i).getMeasuredWidth();            }        }    }    //初始化手势监听对象,使用GestureDetector.OnGestureListener的实现抽象类,因为实际开发中好多方法用不上    private final GestureDetector.OnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener() {        @Override        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {            Log.d("GestureDemoView", "onScroll() distanceX = " + distanceX + " getScrollX = " + getScrollX() + " max_scrollX = " + m_max_scrollX);            int scrollX = getScrollX();            int minScrollX = -scrollX;            int maxScrollY = m_max_scrollX - scrollX;            // 对滑动的距离边界控制            if (distanceX > maxScrollY) {                distanceX = maxScrollY;            } else if (distanceX < minScrollX) {                distanceX = minScrollX;            }//            m_scroller.startScroll(m_scroller.getFinalX(), m_scroller.getFinalY(), m_scroller.getFinalX() + (int) distanceX, 0);            scrollBy((int) distanceX, 0);            return true;        }        @Override        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {            Log.d("GestureDemoView", "onFling() velocityX = " + velocityX);            if (velocityX < 0) {                //快速向左滑动                show_right_view();            } else {                hide_right_view();            }            return super.onFling(e1, e2, velocityX, velocityY);        }    };    private void show_right_view() {        //3,开启滑动条        // 注意:前两个参数为起始滑动点,后2个参数为滑动距离        m_scroller.startScroll(getScrollX(), 0, m_max_scrollX-getScrollX(), 0);        //这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果        invalidate();//        scrollTo(m_max_scrollX, 0);    }    private void hide_right_view() {        // 注意:前两个参数为起始滑动点,后2个参数为滑动距离        m_scroller.startScroll(getScrollX(), 0, 0 - getScrollX(), 0);        invalidate();//        scrollTo(0, 0);    }    @Override    public void computeScroll() {        //4,调用view自身的scrollTo()滑动        if (m_scroller.computeScrollOffset()) {//计算滑动值,并判断是否结束false表示结束            // 两个参数为相对父布局的绝对坐标,这里去Scroller计算出来的当前滑动值            scrollTo(m_scroller.getCurrX(), m_scroller.getCurrY());            postInvalidate();        }    }}

Scroller就像属性动画中的ValueAnimator,他只产生一段连续的值,而不做处理,需要view根据自身的情况去处理这些值,目前看好像只用在scrollTo()或scrollBy()中。
还可以控制动画时间,调用5个参数的startScroll()即可:

    /**     * Start scrolling by providing a starting point, the distance to travel,     * and the duration of the scroll.     *      * @param startX Starting horizontal scroll offset in pixels. Positive     *        numbers will scroll the content to the left.     * @param startY Starting vertical scroll offset in pixels. Positive numbers     *        will scroll the content up.     * @param dx Horizontal distance to travel. Positive numbers will scroll the     *        content to the left.     * @param dy Vertical distance to travel. Positive numbers will scroll the     *        content up.     * @param duration Duration of the scroll in milliseconds.     */    public void startScroll(int startX, int startY, int dx, int dy, int duration) {    }

ListView滑动删除

单个item的滑动效果已经出来了,那么顺便将其集成在ListView中,做成滑动删除效果也不错,效果图如下:
这里写图片描述
实现起来并不难,主要解决的问题就是:如何处理滑动冲突:左右滑动时,若上下滑动父控件(ListView)会拦截滑动事件,去做上下滑动。这时,子view(ViewGroup)就只接收到一个MotionEvent.ACTION_CANCEL事件。
如何让子view在滑动时,提醒父控件不要拦截事件,将事件传递下去呢?我之前在子View中,设置一个flag用来标识view在滑动状态,然后ListView去根据这个值判断是否拦截滑动事件,这样做起来有些bug,在偶然看listview源码时,看到一个方法可以请求父控件不要拦截touch事件,这个事件就是requestDisallowInterceptTouchEvent(true),在AbsListView.startScrollIfNeeded()方法中。
有了这个方法,实现起来简单很多,只要在左右开始滑动时,请求父类不要拦截,我们自己讲touch事件消耗即可。记住要在ACTION_UP时,将其还原为false.直接上代码:
GestureDemoView:

package com.example.y2222.myview;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.animation.LinearInterpolator;import android.widget.LinearLayout;import android.widget.Scroller;import android.widget.TextView;import com.example.y2222.myapplication.R;/** * Created by raise.yang on 2016/06/29. */public class GestureDemoView extends LinearLayout {    private GestureDetector m_gestureDetector;    private Scroller m_scroller;    private int m_max_scrollX;    private TextView m_primary;    public GestureDemoView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public GestureDemoView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        //设置为可点击        setClickable(true);        m_gestureDetector = new GestureDetector(context, onGestureListener);        m_gestureDetector.setIsLongpressEnabled(false);        LayoutInflater.from(context).inflate(R.layout.view_gesture, this);        m_scroller = new Scroller(getContext(), new LinearInterpolator());    }    @Override    protected void onFinishInflate() {        super.onFinishInflate();        m_primary = (TextView) findViewById(R.id.primary_text);    }    public void setPrimaryText(String text) {        m_primary.setText(text);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        Log.d("GestureDemoView", "onTouchEvent() ");        m_gestureDetector.onTouchEvent(event);        if (event.getAction() == MotionEvent.ACTION_UP) {            // 抬起手指,请求父类可以拦截touch事件            requestDisallowInterceptTouchEvent(false);            int scrollX = getScrollX();            if (scrollX > m_max_scrollX / 2) {                show_right_view();            } else {                hide_right_view();            }        }        // 返回true,将此事件消耗,父类就不会处理onTouchEvent事件        return true;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);            if (i == 1) {                m_max_scrollX = getChildAt(i).getMeasuredWidth();            }        }    }    private final GestureDetector.OnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener() {        @Override        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {            Log.d("GestureDemoView", "onScroll() distanceX = " + distanceX + " getScrollX = " + getScrollX() + " max_scrollX = " + m_max_scrollX);            int scrollX = getScrollX();            int minScrollX = -scrollX;            int maxScrollY = m_max_scrollX - scrollX;            // 对滑动的距离边界控制            if (distanceX > maxScrollY) {                distanceX = maxScrollY;            } else if (distanceX < minScrollX) {                distanceX = minScrollX;            }            scrollBy((int) distanceX, 0);            //当前view开始滑动,请求父类不要拦截move事件            requestDisallowInterceptTouchEvent(true);            return true;        }        @Override        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {            Log.d("GestureDemoView", "onFling() velocityX = " + velocityX);            if (velocityX < 0) {                //快速向左滑动                show_right_view();            } else {                hide_right_view();            }            return super.onFling(e1, e2, velocityX, velocityY);        }    };    private void show_right_view() {        m_scroller.startScroll(getScrollX(), 0, m_max_scrollX - getScrollX(), 0, 100);        invalidate();    }    private void hide_right_view() {        m_scroller.startScroll(getScrollX(), 0, 0 - getScrollX(), 0, 100);        invalidate();    }    @Override    public void computeScroll() {        if (m_scroller.computeScrollOffset()) {//计算滑动值,并判断是否结束false表示结束            scrollTo(m_scroller.getCurrX(), m_scroller.getCurrY());            postInvalidate();        }    }    public void initViewPosition() {        scrollTo(0, 0);    }}

GestureActivity:

package com.example.y2222.myapplication;import android.app.Activity;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ListView;import com.example.y2222.myview.GestureDemoView;public class GestureActivity extends Activity {    private ListView m_listView;    private String[] m_datas = new String[]{            "1", "2", "3", "4", "5",            "6", "7", "8", "9", "10",    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_gesture);        m_listView = (ListView) findViewById(R.id.listview);        m_listView.setAdapter(new Adapter());    }    class Adapter extends BaseAdapter {        @Override        public View getView(int position, View convertView, ViewGroup parent) {            if (convertView == null) {                convertView = LayoutInflater.from(GestureActivity.this).inflate(R.layout.item_slide_listview, parent, false);            }            GestureDemoView root = (GestureDemoView) convertView;            root.setPrimaryText(getItem(position));            root.initViewPosition();            return convertView;        }        @Override        public int getCount() {            return m_datas.length;        }        @Override        public String getItem(int position) {            return m_datas[position];        }        @Override        public long getItemId(int position) {            return position;        }    }}

item的布局文件:

<?xml version="1.0" encoding="utf-8"?><com.example.y2222.myview.GestureDemoView xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="80dp"></com.example.y2222.myview.GestureDemoView>

Activity的布局文件:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@android:color/holo_blue_light"    tools:context="com.example.y2222.myapplication.GestureActivity">    <ListView        android:id="@+id/listview"        android:layout_width="match_parent"        android:layout_height="match_parent"/></RelativeLayout>
1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 买家申请退款卖家不退款怎么办 卖家恶意不退款怎么办 欠条到期了对方不还钱怎么办 冰箱磕了一坑怎么办 办信用卡没有家庭地址的怎么办 钱付了货没收到怎么办 在苏宁易购上买东西地址错了怎么办 手机分期付款银行卡丢了怎么办 华硕笔记本鼠标不动了怎么办 韵达快递不派送怎么办 中通快递不派送怎么办 农业银行信用卡密码输错三次怎么办 农业银行卡多次输错密码怎么办 想把店长弄走怎么办 济南银座卡过期了怎么办 银座购物卡丢失后怎么办 银座的卡丢了怎么办 银行卡换了旧卡怎么办 大理市民卡丢了怎么办 市民卡内的钱怎么办 宝付支付乱扣款怎么办 苏宁任性贷逾期怎么办 第二次跟家里开口要钱还网贷怎么办 网贷到家来要钱怎么办 网贷贷不了啦急要钱怎么办 百度推广竞价关键词太长怎么办 药店位置差客流少怎么办 网站上的用词违规怎么办 苹果16g内存不够怎么办 手机16g内存不够怎么办 在私企年纪大了怎么办 谷歌浏览器显示不安全打不开怎么办 4s密码多次错误怎么办 苹果4s手机系统错误怎么办 汽车充电口坏了怎么办 如果手机充不了电怎么办 淘宝买的家电坏了怎么办 衣服皱了没有熨斗怎么办 油烟机油盒坏了怎么办 实体店不给换货怎么办 台式电脑鼠标不动了怎么办