目录

  • 安卓View — View (一)
    • 一、 View的基础知识
      • 1.什么是View
      • 2.View的位置参数
      • 3.MotionEvent
      • 4.TouchSlop
      • 5.VelocityTracker
      • 6.GestureDetector
    • 二、View的滑动
      • 1.scrollTo/scrollBy
      • 2.使用动画
        • View动画
        • 属性动画
      • 3.改变布局参数
      • 4.滑动方式对比
      • 5.跟随手指滑动的View编写
    • 三.弹性滑动
      • 1. Scroller
      • 2.使用动画
      • 3.使用延时策略

安卓View — View (一)

一、 View的基础知识

1.什么是View

在Android中, 控件大致被分为两类,即ViewGroup和View, ViewGroup作为父控件可以包含多个View, 并管理其包含的View控件, View是Android中所有控件的基类,是界面层的空间的一种抽象它代表了一个控件。

2.View的位置参数

View的位置参数主要有

参数名 含义
top View左上角到父容器顶部的像素距离
left View左上角到父容器左边边缘像素距离
bottom View右下角到父容器顶部的像素距离
right View右下角到父容器左边边缘像素距离
x/y View左上角坐标
translationX/translationY View左上角相对于父容器的偏移量

坐标系以父布局左上角为基准的

3.MotionEvent

MotionEvent是指触摸事件的相关细节,在手指触摸时发生的一系列事件中经典的事件有以下几种:

  • ACTION_DOWN 手指刚接触屏幕
  • ACTION_MOVE 手指在屏幕上移动
  • ACTION_UP 手指从屏幕松开的一瞬间
  • ACTION_CANCEL 时间结束(非人为原因)

通过MotionEvent可以获取到触摸事件的x和y坐标

  • getX/getY 相对于View左上角的x与y坐标
  • getRawX/getRawY 相对于屏幕左上角的x与y坐标

正常情况下,一次手指触摸的行为会触发一系列点击事件,如:

  • 点击屏幕后立刻松开,ACTION_DOWN -> ACTION_UP
  • 点击屏幕后滑动手指后再松开,ACTION_DOWN -> ACTION_MOVE -> … -> ACTION_UP

事件序列:

4.TouchSlop

TouchSlop是系统所能识别的被认为是滑动的最小距离。这是一个常量和设备有关,不同的设备获取的值可能不同。如果滑动起始位置与结束位置的距离小于这个常量可以认为未达到滑动距离的临界值因此认定这个不是滑动提高用户体验。

可以通过以下代码获取:

ViewConfiguration.get(getContext()).getScaledTouchSlop();

5.VelocityTracker

VelocityTracker为速度追踪器,用于追踪手指在滑动过程中的速度,包括水平与竖直方向的速度。

使用方法:

//在onTouchEvent方法中追踪当前点击事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);//获取在1000ms内中手指滑过的像素
//速度 =(终点位置 - 起点位置)/ 时间段
velocityTracker.computeCurrentVelocity(1000);
float xVelocity = velocityTracker.getXVelocity();
float yVelocity = velocityTracker.getYVelocity();//在不需要使用时调用clear与recycle来重置并回收内存
velocityTracker.clear();
velocityTracker.recycle();

注意:和Android坐标轴相同方向结果为正,相反方向为负

6.GestureDetector

手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。

GestureDetector内部的Listener接口:

  • OnGestureListener,这个Listener监听一些手势,如单击、滑动、长按等操作:
  • OnDoubleTapListener,这个Listener监听双击和单击事件。
  • OnContextClickListener,鼠标右键(加入外设)
  • SimpleOnGestureListener,实现了上面三个接口的类,拥有上面三个的所有回调方法。
package com.skit.view;import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;/*** Author: shuike,* Email: shuike007@126.com,* Date: 2019/11/25.* PS:*/
public class MainActivity extends AppCompatActivity {GestureDetector.SimpleOnGestureListener simpleOnGestureListener = new GestureDetector.SimpleOnGestureListener(){//手指轻触并松开@Overridepublic boolean onSingleTapUp(MotionEvent e) {return super.onSingleTapUp(e);}//长按@Overridepublic void onLongPress(MotionEvent e) {super.onLongPress(e);}//按下并拖动@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {return super.onScroll(e1, e2, distanceX, distanceY);}//按下触碰长按并松开@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {return super.onFling(e1, e2, velocityX, velocityY);}//手指轻触屏幕的一瞬间,尚未松开@Overridepublic void onShowPress(MotionEvent e) {super.onShowPress(e);}//手指轻触屏幕的一瞬间@Overridepublic boolean onDown(MotionEvent e) {return super.onDown(e);}//双击@Overridepublic boolean onDoubleTap(MotionEvent e) {return super.onDoubleTap(e);}//发生双击并松开@Overridepublic boolean onDoubleTapEvent(MotionEvent e) {return super.onDoubleTapEvent(e);}//严格的单击@Overridepublic boolean onSingleTapConfirmed(MotionEvent e) {return super.onSingleTapConfirmed(e);}//鼠标右键点击时的回调@Overridepublic boolean onContextClick(MotionEvent e) {return super.onContextClick(e);}};@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final GestureDetector gestureDetector = new GestureDetector(this, simpleOnGestureListener);View view = findViewById(R.id.view);view.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {return gestureDetector.onTouchEvent(event);}});}
}

比较常用的:

  • onSingleTapUp(单击)
  • onFling(快速滑动)
  • onScroll(拖动)
  • onLongPress(长按)
  • onDoubleTap(双击)

二、View的滑动

1.scrollTo/scrollBy

为了实现View的滑动,View提供了专门的方法来实现这个功能

scrollTo/scrollBy的区别:

  • scrollTo是基于参数的绝对滑动。
  • scrollBy是基于参数的相对滑动。
  • 注意,两者都是移动View的内容,而不是VIew本身

scrollTo与scrollBy源码

    /*** Set the scrolled position of your view. This will cause a call to* {@link #onScrollChanged(int, int, int, int)} and the view will be* invalidated.* @param x the x position to scroll to* @param y the y position to scroll to*/public void scrollTo(int x, int y) {if (mScrollX != x || mScrollY != y) {int oldX = mScrollX;int oldY = mScrollY;mScrollX = x;mScrollY = y;invalidateParentCaches();onScrollChanged(mScrollX, mScrollY, oldX, oldY);if (!awakenScrollBars()) {postInvalidateOnAnimation();}}}/*** Move the scrolled position of your view. This will cause a call to* {@link #onScrollChanged(int, int, int, int)} and the view will be* invalidated.* @param x the amount of pixels to scroll by horizontally* @param y the amount of pixels to scroll by vertically*/public void scrollBy(int x, int y) {//可以看出scrollBy也是调用scrollBy实现的scrollTo(mScrollX + x, mScrollY + y);}

在滑动过程中:

  • mScrollX的值总是等于View的左边缘和View的内容左边缘在水平方向的距离。

  • mScrollY的值总是等于View的上边缘和View的内容上边缘在竖直方向的距离

mScrollX与mScrollY只能改变View的内容的位置而不能改变View在布局中的位置。mScrollX和mScrollY的值单位是像素,从左向右滑动mScrollX值为负,否则为正,从上往下滑动mScrollY值为负,否则为正。

2.使用动画

通过动画我们能让一个View进行平移,而平移就是一种滑动。使用动画来移动View主要是操作View的translationX与translationY,可以使用View补间动画或属性动画。

View动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true"><translateandroid:duration="100"android:fromXDelta="0"android:fromYDelta="0"android:interpolator="@android:anim/linear_interpolator"android:toXDelta="100"android:toYDelta="100" />
</set>
Animation animation = AnimationUtils.loadAnimation(this,R.anim.view_translate);
view.startAnimation(animation);

通过GIF可以看出来 View动画是对View的影像进行操作的,也就是说View动画并不能真正的改变View的位置。

属性动画

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"translationX",0,100).setDuration(1000);
objectAnimator.start();

通过GIF可以看出来属性动画是真正改变View的位置。

但它是从Android3.0开始推出的。

3.改变布局参数

改变布局参数,即会改变LayouParams的参数,如:要将一个View右移100像素点,我们可以把该View的LayoutParams的marginLeft参数增加100就可以实现

ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
params.leftMargin += 100;
view.requestLayout();
//或者
//view.setLayoutParams(params);

4.滑动方式对比

上面分别使用三种方式实现了View的滑动,那么各个方式的区别是什么样的呢?

方式 优点 缺点
scrollTo/scrollBy 原生方法 只能滑动View内容,不能滑动View本身
动画 操作简单、适用于没有交互的View和复杂的动画效果 Android3.0以下不兼容
改变布局参数 适用于有交互的View 操作稍微复杂

5.跟随手指滑动的View编写

@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getRawX();float y = event.getRawY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:break;case MotionEvent.ACTION_MOVE:float deltaX = x - mLastX;float deltaY = y - mLastY;float translationX = (getTranslationX() + deltaX);float translationY = (getTranslationY() + deltaY);setTranslationX(translationX);setTranslationY(translationY);break;}mLastX = x;mLastY = y;return true;}

三.弹性滑动

1. Scroller

Scroller弹性滑动对象,用于实现View的弹性滑动,在使用View的scrollTo/scroolBy方法来滑动时过程是一瞬间完成的,没有过渡效果对用户体验不好,这时可以使用Scroller来实现过度滑动,Scroller本身无法让View弹性滑动,需要配合、View的computeScroll方法配合使用。

使用方法:

 //第一步private Scroller mScroller;mScroller = new Scroller(context);//第二步,调用startScroll()方法来初始化滚动数据并刷新界面mScroller.startScroll(getScrollX(), 0, dx, 0);//第三步,重写computeScroll方法,并在其内部完成平滑滚定的逻辑@Overridepublic void computeScroll() {if(mScroller.computeScrollOffset()){scrollTo(mScroller.getCurrX(), mScroller.getCurrY());postInvalidate();}}

Scroll相关源码:

//startX与startY为滑动的起点,dx与dy为要滑动的距离,duration为滑动的时间默认为250
public void startScroll(int startX, int startY, int dx, int dy, int duration) {mMode = SCROLL_MODE;//模式在之后的computeScrollOffset做判断使用mFinished = false;mDuration = duration;mStartTime = AnimationUtils.currentAnimationTimeMillis();mStartX = startX;mStartY = startY;mFinalX = startX + dx;mFinalY = startY + dy;mDeltaX = dx;mDeltaY = dy;mDurationReciprocal = 1.0f / (float) mDuration;}public boolean computeScrollOffset() {if (mFinished) {return false;}int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);if (timePassed < mDuration) {switch (mMode) {case SCROLL_MODE:final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);mCurrX = mStartX + Math.round(x * mDeltaX);mCurrY = mStartY + Math.round(x * mDeltaY);break;.....}}else {mCurrX = mFinalX;mCurrY = mFinalY;mFinished = true;}return true;}

2.使用动画

动画本身就是一种渐进的过程,因此通过它来实现的滑动天然就具有弹性效果,比如将一个View在100ms内向右移动100像素。

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view,"translationX",0,100).setDuration(1000);
objectAnimator.start();

3.使用延时策略

    private static final int MESSAGE_SCROLL_TO = 1;private static final int FRAME_COUNT = -300;private static final int DELAYED_TIME = 10;Handler mHandler = new Handler(){@Overridepublic void handleMessage(@NonNull Message msg) {switch (msg.what) {case MESSAGE_SCROLL_TO:Toast.makeText(MainActivity.this, "shoudaole", Toast.LENGTH_SHORT).show();mCount++;if (mCount >= FRAME_COUNT) {float fraction = mCount / FRAME_COUNT;int scrollX = (int) (fraction * 100);view.scrollTo(scrollX, 0 );mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO, DELAYED_TIME);}break;}}};

安卓View — View (一)相关推荐

  1. 安卓自定义view全解:初始化,onDraw函数,onMeasure函数,用户手势事件

    全栈工程师开发手册 (作者:栾鹏) 安卓教程全解 安卓自定义view全解. view类包含如下函数.可供重写. onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后 ...

  2. 安卓自定义view中 绘画基本图形点线面,矩形,方形,圆,扇形,文字及沿着特定方向布局,自定义圆角ImageView图片等等相关api使用方法及举例

    安卓自定义view中 绘画基本图形点线面,矩形,方形,圆,扇形,文字及沿着特定方向布局,自定义圆角ImageView图片等等相关api使用方法及举例,图片压缩处理逻辑 本文旨在介绍自定义View的实现 ...

  3. android控件向内弧度_安卓自定义 View 基础:坐标系、角度弧度、颜色

    安卓自定义View基础 - 坐标系 一.屏幕坐标系和数学坐标系的区别 由于移动设备一般定义屏幕左上角为坐标原点,向右为x轴增大方向,向下为y轴增大方向, 所以在手机屏幕上的坐标系与数学中常见的坐标系是 ...

  4. 安卓自定义View的状态保存与恢复

    安卓自定义View的状态保存与恢复 我们在开发某些安卓应用(如安卓小游戏)时,可能会用到自定义View,这时候往往需要保存自定义View的状态信息,以便在遇到某些情况(如由于系统内存资源紧张被系统杀死 ...

  5. 安卓自定义View实现加载gif图片

    开题:加载GIF的场景在安卓开发中还比较常见,网上也有一些三方法的框架会支持对gif的加载,在上篇博客为大家推荐的图片加载库Glide也支持gif的加载Glide工具类的简单封装,今天给大家分享通过自 ...

  6. 安卓自定义View——网易颜色渐变效果指示器

    一直想写博客来着,可惜直到现在才真正抽出时间.最近一直在研究网易新闻这个UI框架,发现了一些很值得借鉴的效果,当然,网上也不乏这方面的介绍.本文主要实现的指示器效果为字体颜色和大小渐变,废话不多说献上 ...

  7. 安卓自定义View进阶-事件分发机制原理

    之前讲解了很多与View绘图相关的知识,你可以在 安卓自定义View教程目录 中查看到这些文章,如果你理解了这些文章,那么至少2D绘图部分不是难题了,大部分的需求都能满足,但是关于View还有很多知识 ...

  8. 安卓自定义View进阶-分类与流程

    自定义View绘制流程函数调用链(简化版) 一.自定义View分类 我将自定义View分为了两类(sloop个人分类法,非官方): 1.自定义ViewGroup 自定义ViewGroup一般是利用现有 ...

  9. 安卓自定义view之——可滑动时间轴(时间刻度尺)

    如果需要解决在viewpager,horizontalscrollview中滑动事件的冲突,可注入viewpager,horizontalscrollview对象,在down move的时候调用req ...

最新文章

  1. R语言使用ggplot2可视化堆叠条形图,并在堆叠条形图上显示数据值实战
  2. linux 命令行选项
  3. 【学习笔记】【C语言】类型说明符
  4. 声明为指针,定义为数组,声明为数组,定义为指针
  5. NOIP2016普及组第一题:买铅笔
  6. devops项目经理_DevOps:如何避免交接导致项目死亡
  7. 百度2017春招笔试
  8. jmeter 连接 sqlite 进行压力测试
  9. [转载] python 需求清单_Python清单操作摘要
  10. Oracle客户端安装教程(图文)
  11. Mac读写NTFS移动硬盘
  12. 微信小程序-云开发数据库基础操作(自用)
  13. 低功耗设计实现中secondary power pin的连接方法汇总
  14. QQ计数器统计器使用教程
  15. 论车牌识别与电子警察关系
  16. 阿里云数据库RDS如何监控、备份及克隆实例?
  17. (原创)android6.0系统 PowerManager深入分析(很具体)
  18. DirectX11--实现一个3D魔方(3)
  19. 微积分在金融投资的应用
  20. 【pyecharts50例】xy轴翻转(reversal_axis)

热门文章

  1. 又见block(一):block是什么?
  2. C语言 | 栈区空间初探
  3. 【GAOPS002】round robin Verilog实现
  4. sql between包括两端吗?
  5. 比较DirectX和OpenGL的区别
  6. MockMvc案例实战调用Controller层API接⼝
  7. js中回调函数的理解 举例说明js回调函数
  8. 关于Cron表达式中的周一至周五正确的配置
  9. echart 图表类型
  10. qt的四舍五入_string.format 小数点 QT 对于float类型四舍五入