View滑动的基本思想:当点击事件传到View时,系统记下触摸点的坐标,手指移动时系统记下触摸后的坐标并计算出偏移量,然后根据偏移量修正View坐标.

实现View滑动共有6种方法:layout()方法,offsetTopAndBottom(),LayoutParams,动画,scrollTo与scrollBy,以及Scroller.

一.layout()

import ...;

public class CustomView extends View {
private int lastX;
private int lastY; public CustomView(Context context) {
super(context);
} public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
} public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public CustomView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
} @Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY(); switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
        //获取手指按下时,触摸点位置
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
        //获取移动后触摸点位置,计算偏移量
int offsetX = x - lastX;
int offsetY = y - lastY;
        //修改View的left,top,right,bottom属性重新放置View
layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
break;
}
return true;
}
}

然后在布局文件中引用就好了:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
> <com.example.scroll_test.CustomView
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@color/colorAccent"
/> </LinearLayout>

二.offsetLeftandRight

这种方法与Layout()方法相似,只需将ACTION_MOVE修改成以下代码:

            case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX;
int offsetY = y - lastY;
offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);
break;
}

三.LayoutParams(改变布局参数)

通过LayoutParams改变View的布局参数,从而达到修改View位置的效果.

将ACTION_MOVE修改成以下代码:

            case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX;
int offsetY = y - lastY;
          
LinearLayout.LayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin=getLeft() + offsetX;
layoutParams.topMargin=getTop() + offsetY;
setLayoutParams(layoutParams);
break;
}

由于父控件是LinearLayout,所以用到了LineatLayout.LayoutParams.如果是RelativeLayout,则要使用RelativeLayot.LayoutParams.还可以用ViewGroup.MarginLayoutParams来实现:

ViewGroup.MarginLayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin=getLeft() + offsetX;
layoutParams.topMargin=getTop() + offsetY;
setLayoutParams(layoutParams);

四.属性动画

ObjectAnimator.ofFloat(mCustomView,"translationX",0,300).setDuration().start();

五.scrollTo与scrollBy

scrollTo(x,y)表示移动到一个具体的点,scrollBy(dx,dy)表示移动的增量为dx,dy.

scrollTo,scrollBy移动的是View的内容,如果在ViewGround中使用,则是移动其所有的子View..我们将ACTION_MOVE替换成如下代码:

((View)getParent()).scrollBy(-offsetX,-offsetY);

设置为负值,则CustomView会跟随手滑动.原因是因为此时移动的是手机屏幕,布局是不移动的.布局中的控件也是不懂的,手指向右滑动后,想要View也向右滑动,则要把手机屏幕向着左边滑动,则布局相对向右滑动,实现跟手的效果.

六.Scroller

这个方法的实现效果比较类似动画,不过与动画相比其只可以用来实现滑动效果.

首先要初始化这个scroller:

public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
scroller=new Scroller(context);
}

接下来重写computeScroll()方法,该方法会在View绘制时的draw()中调用

@Override
public void computeScroll() {
super.computeScroll();
if(scroller.computeScrollOffset()){
((View)getParent()).scrollTo(scroller.getCurrX(),scroller.getCurrY());
//通过不断调用invalidate(),不断返回调用computeScroll,更新View位置
      // 直到scroller.computeScrolloffset返回fasle(即dutation结束)
      invalidate();
}
}

同时在CustomView中写一个方法:

 public void smoothScrollTo(int destX,int dextY){
int scrollX=getScrollX();
int deltaX=destX-scrollX;      //startScroll (int startX, int startY, int dx, int dy, int duration)
        scroller.startScroll(scrollX,0,deltaX,0,2000);
invalidate();
}

通过在代码中调用自定义控件的smoothScrollTo方法,可以实现View的滑动效果.

												

View体系第二篇:View滑动的更多相关文章

  1. Android学习笔记(第二篇)View中的五大布局

    PS:人不要低估自己的实力,但是也不能高估自己的能力.凡事谦为本... 学习内容: 1.用户界面View中的五大布局... i.首先介绍一下view的概念   view是什么呢?我们已经知道一个Act ...

  2. View体系第一篇:基础

    View体系的学习内容为学习刘望舒先生博客总结的内容,大家可到他的博客看到更详细的内容. 一.view之间的继承关系 Viewground用来包裹其他view.在平常的使用中,我们不会直接用到View ...

  3. 《Android进阶之光》--View体系与自定义View

    No1: View的滑动 1)layout()方法的 public class CustomView extends View{ private int lastX; private int last ...

  4. Android View体系(一)视图坐标系

    前言 Android View体系是界面编程的核心,他的重要性不亚于Android四大组件,在这个系列中我会陆续讲到View坐标系.View的滑动.View的事件分发等文章来逐步介绍Android V ...

  5. Android View体系(四)从源码解析Scroller

    在Android View体系(二)实现View滑动的六种方法这篇文章中我们讲到了用Scroller来实现View的滑动,所以这篇文章我们就不介绍Scroller是如何使用的了,本篇就从源码来分析下S ...

  6. android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

    我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...

  7. Android View体系(三)属性动画

    上一篇文章讲了View滑动的六种方法,其中一种是使用动画,这篇文章我们来讲一讲动画的其中一种:属性动画. 1.android视图动画和属性动画 视图动画我们都了解,它提供了AlphaAnimation ...

  8. Android View体系(八)从源代码解析View的layout和draw流程

    相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...

  9. Android View体系(十)自定义组合控件

    相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...

随机推荐

  1. mysql 开发进阶篇系列 20 MySQL Server(innodb_lock_wait_timeout,innodb_support_xa,innodb _log_*)

    1. innodb_lock_wait_timeout mysql 可以自动监测行锁导致的死锁并进行相应的处理,但是对于表锁导致的死锁不能自动监测,所以该参数主要用于,出现类似情况的时候等待指定的时间 ...

  2. mysql 开发进阶篇系列 17 MySQL Server(key_buffer与table_cache)

    一.key_buffer 上一篇了解key_buffer设置,key_buffer_size指定了索引缓冲区的大小,它决定索引处理的速度,尤其是索引读的速度.通过检查状态值Key_read_reque ...

  3. 改变input的值不会触发change事件的解决思路

    通常来说,如果我们自己通过 value 改变了 input 元素的值,我们肯定是知道的,但是在某些场景下,页面上有别的逻辑在改变 input 的 value 值,我们可能希望能在这个值发生变化的时候收 ...

  4. C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解

    剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...

  5. 并发服务器三种实现方式之进程、线程和select

    前言:刚开始学网络编程,都会先写一个客户端和服务端,不知道你们有没有试一下:再打开一下客户端,是连不上服务端的.还有一个问题不知道你们发现没:有时启服务器,会提示“Address already in ...

  6. 解决:MVC对象转json包含\r \n

    项目中对象转json字符串时,如下:JsonSerializerSettings jsetting = new JsonSerializerSettings(); jsetting.DefaultVa ...

  7. C++ STL中的map用红黑树实现,搜索效率是O(lgN),为什么不像python一样用散列表从而获得常数级搜索效率呢?

    C++ STL中的标准规定: map, 有序 unordered_map,无序,这个就是用散列表实现 谈谈hashmap和map的区别,我们知道hashmap是平均O(1),map是平均O(lnN)的 ...

  8. Perl的列表和数组

    列表和数组 列表 使用括号包围的元素,括号中的元素使用逗号隔开的是列表. 列表中的元素可以是字符串.数值.undef或它们的混合. 列表中的字符串元素需要使用引号包围. 空列表是括号中什么都没有的列表 ...

  9. Perl的输出:print、say和printf、sprintf

    print.printf和say都可以输出信息.print和say类似,print不自带换行符,say自带换行符,但要使用say,必须写use语句use 5.010;,printf像C语言的print ...

  10. Go基础系列:惰性数值生成器

    惰性数值生成器是指在需要的时候才生成下一个数值,不需要的时候就卡在那.这和python的列表推导表达式类似.惰性生成器的好处是不会一次性将全部结果返回或放进内存,而是每次只返回一个,这样不会在某一时刻 ...