自定义控件之滑动

来源:互联网 发布:ios11更新不了软件 编辑:程序博客网 时间:2024/06/05 19:25

View滑动的方法是现实绚丽的自定义控件的基础

一般来说实现滑动的方法有三种:

  1. 通过View本身提供的scrollTo/scrollBy方法来实现
  2. 通过动画方法
  3. 通过更改View的LayoutParams,实现重新布局来实现。

一、通过View本身提供的scrollTo/scrollBy方法来实现

scrollTo/scrollBy改变的是控件的内容的而不是控件在布局中的位置。例如设置一个长宽高都是100dp的TextView,效果如下:

scrollTo使用方法是:

/** * x:是在x轴上的偏移量 * y:是在y轴上的偏移量 * 例如从(0,0)偏移到(20,20),那么x=0-20=-20,  y=0-20=-20 * 所以,如果从上向下,从左向右,那么偏移量x,y为负值,反之为正值。 */tv.scrollTo(int x,int y);

scrollBy可以多次偏移,再次偏移的时候就以上次偏移的位置作为起始点。具体效果如上图。

tv.scrollBy(int x,int y);

二、通过动画方式

动画的部分下次会详细描述,这次略过。

三、通过更改View的LayoutParams,实现重新布局来实现。

制作一个翻页的界面,在翻页的时候小圆点跟着变化,效果如下:

查看主要代码:

xml布局:

<RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_test3"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="cn.centran.zx_view_custom.Test3Activity">    <android.support.v4.view.ViewPager        android:id="@+id/vp_guide"        android:layout_width="match_parent"        android:layout_height="match_parent" />    <RelativeLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_centerHorizontal="true"        android:layout_marginBottom="30dp" >        <LinearLayout            android:id="@+id/ll_point_group"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:orientation="horizontal" >        </LinearLayout>        <View            android:id="@+id/view_red_point"            android:layout_width="10dp"            android:layout_height="10dp"            android:background="@drawable/shape_point_selected" />    </RelativeLayout></RelativeLayout>

重要代码片段:

/** * 加载小圆点 */for(int i=0;i<imageId.length;i++){    View point = new View(this);    //设置圆点背景    point.setBackgroundResource(R.drawable.shape_point_normal);    //设置圆点宽高    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(30,30);    point.setLayoutParams(params);    if(i!=0){        params.leftMargin = 30;    }    llPointGroup.addView(point);}/**     * 获取两个圆点之间的距离     */    //获取视图树    final ViewTreeObserver viewTreeObserver = llPointGroup.getViewTreeObserver();    //添加对试图树中layout过程的监控    viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)        @Override        public void onGlobalLayout() {            System.out.println("layout");            llPointGroup.getViewTreeObserver().removeOnGlobalLayoutListener(this);            pointWidth = llPointGroup.getChildAt(1).getLeft() - llPointGroup.getChildAt(0).getLeft();        }    });/**     * 监控ViewPager的滑动     */    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {        @Override        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            System.out.println("position::"+position+"   positionOffset::"+positionOffset+"  positionOffsetPixels::"+positionOffsetPixels);            int offset = (int) (pointWidth * positionOffset+pointWidth*position);            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mRedPoint.getLayoutParams());            params.leftMargin = offset;            mRedPoint.setLayoutParams(params);        }        @Override        public void onPageSelected(int position) {        }        @Override        public void onPageScrollStateChanged(int state) {        }    });

VelocityTracker介绍:
VelocityTracker是速度跟踪器,用于跟踪手指在滑动过程中的速度,包括竖直速度和水平速度。

//获取速度跟踪器的对象velocityTracker = VelocityTracker.obtain();@Overridepublic boolean onTouchEvent(MotionEvent event) {    //添加速度跟踪器监控的事件    velocityTracker.addMovement(event);    switch (event.getAction()){        case MotionEvent.ACTION_MOVE:            /**             * 设置速度跟踪器的时间段             * 1000:表示跟踪1s中滑过的像素             */            velocityTracker.computeCurrentVelocity(1000);            xVelocity = velocityTracker.getXVelocity();            yVelocity = velocityTracker.getYVelocity();            break;        case MotionEvent.ACTION_UP:            Toast.makeText(Test4Activity.this, "水平速度::"+xVelocity+"   竖直速度::"+yVelocity, Toast.LENGTH_SHORT).show();            break;        default:break;    }    return super.onTouchEvent(event);}/**     * 当不使用的时候,重置以及释放内存     */    velocityTracker.clear();    velocityTracker.recycle();

因为: 速度 = (终点位置 - 起点位置) / 时间段 , 所以速度有正负值,向下/向右滑动,水平/竖直的速度为正值,反之为负值。

GestureDector详解:

手势检测器,虽然android中有onTouch()方法,但是这个方法太简单了,如果需要处理一些复杂的手势,那么就需要用到gestureDector。

GestureDector这个类提供了两个接口和一个类。

  1. OnGestureListener接口
  2. OnDoubleTapListener接口
  3. SimpleOnGestureListener,此类继承了上面两个接口的所有方法,需要哪个方法就实现哪个方法。

    GestureDetector mGestureDetector = new GestureDetector(mGestureListener); private GestureDetector.OnGestureListener mGestureListener = new GestureDetector.OnGestureListener(){    ......}@Overridepublic boolean onTouch(View v, MotionEvent event) {    return mGestureDetector.onTouchEvent(event);}

弹性滑动:

上面介绍的滑动方法都是生硬的滑动,这次介绍弹性滑动,弹性滑动差不多有三种方法:

  1. 使用Scroller
  2. 通过动画
  3. 通过延时策略

一、使用Scroller

scroller需要与computeScroll配合使用:

Scroller mScroller = new Scroller(context);public void smoothScrollTo(int destX,int destY,int durationTime){    int scrollX = getScrollX();    int scrollY = getScrollY();    mScroller.startScroll(scrollX,scrollX,destX,destY,durationTime);    invalidate();}@Overridepublic void computeScroll() {    super.computeScroll();    if(mScroller.computeScrollOffset()){        scrollTo(mScroller.getCurrX(),mScroller.getCurrY());        postInvalidate();    }}

当调用smoothScrollTo方法的时候,invalidate()方法会导致View重绘。当View重绘后会在draw方法中调用computeScroll,而computeScroll又会去从Scroller中获取当前的scrollX和scrollY;然后又通过scrollTo实现滑动。接着又调用postInvalidate方法来进行绘制,这次绘制又会导致computeScroll方法的调用(注意此时获取的当前的scrollX和scrollY是上次滑动后的位置),如此反复,直至整个滑动过程结束。

二、通过动画方式

动画的部分下次会详细描述,这次略过。

三、通过延时策略方式

private static final int MESSAGE_TAG = 1;private int mCount = 0;private int TOTAL_COUNT = 30;private int DELAY_TIME = 33;public Handler mHandler = new Handler(){    @Override    public void handleMessage(Message msg) {        super.handleMessage(msg);        if(msg.what == MESSAGE_TAG){            mCount++;            if(mCount<TOTAL_COUNT){                int scrollX = -300/TOTAL_COUNT;                btn_moving.scrollBy(scrollX,0);                mHandler.sendEmptyMessageDelayed(MESSAGE_TAG,DELAY_TIME);            }        }    }};
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 两岁儿童打人怎么办 孩子哭闹要东西怎么办 高中孩子爱打架怎么办 宝宝性格太弱怎么办 宝宝太老实了怎么办 一岁多宝宝爱打人怎么办 一岁半宝宝爱打人怎么办 两岁半宝宝喜欢打人怎么办 孩子总是挨欺负怎么办 一年级孩子爱打架怎么办 孩子没规矩家长怎么办 小朋友在幼儿园打人怎么办 幼儿园小朋友喜欢打人怎么办 三周岁宝宝爱哭怎么办 2周岁宝宝爱哭怎么办 一个月宝宝爱哭怎么办 2岁宝宝爱哭怎么办 三岁小朋友打人怎么办 一岁半小朋友喜欢打人怎么办 爷爷偏心我该怎么办 冲动型学生老师怎么办 两个宝宝争东西怎么办 2周岁宝宝打人怎么办 小孩幼儿园被打怎么办 小孩喝了润滑油怎么办 孩子被打了怎么办 宝宝吃了指甲油怎么办 孩子掉了深海怎么办 小孩打了别人怎么办 两岁宝宝爱咬人怎么办 孩子上学老打人怎么办 孩子上学爱说话怎么办 孩子抢玩具打人怎么办 生气就像打人怎么办 小孩总喜欢打人怎么办 小孩性格好翘怎么办 一岁小宝宝打人怎么办 小孩子老喜欢打人怎么办 孩子被大人欺负怎么办 小孩识字量少怎么办 父母打架孩子该怎么办