View的基本概念了解

View方面的东西,乍一眼看去,我真是满脸懵比,雾里看花般难受。

View是所有控件的基类,是一种界面层控件的抽象,代表着一个控件。连ViewGroup都是其子类。而ViewGroup可以直译为控件组,可以包含多个View。

一个View既可以表示一个控件,也可以是多个控件组成的一组控件。

一,View的基础知识

1.1 View的位置参数

一个矩形有四个点,而决定View的位置同样有四个点,分别是left,top,right,bottom。

其中left表示View的左上角距离左边的距离,top表示View的左上角距离上边的距离。

right表示View的右下角距离左边的距离,bottom表示View的右下角距离上边的距离。

当然,这些坐标相对于它的父容器而言的。

View的布局如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

        <asule.myview.ManualView
            android:background="#123456"
            android:layout_centerInParent="true"
            android:layout_width="150dp"
            android:layout_height="150dp" />

</RelativeLayout>

下面父容器指的是RelativeLayout

那么很容易的可以获得View的宽高
    int width=right-left;
    int height=bootom-top;

而得到这个四个位置参数的值,也很简单。
    通过View的getLeft,getRight,getTop,getBottom方法。

在android3.0以后,View中又提供了几个位置参数:x,y,transactionX,transactionY四个参数。

x,y表示的是当前View在父容器中左上角的位置,而transactionX和transactionY表示的是View的左上角相对于父容器的偏移量。

所以android3.0以前,左上角的位置就是(left,top),而现在有了偏移量就变为(left+transactionX,top+transactionY)。

x=left+transactionX;
y=top+transactionY;

而默认情况下,transactionX和transactionY都为0。如下:

System.out.println("transactionX:" + getTranslationX());
System.out.println("transactionY:" + getTranslationY());

System.out: transactionX:0.0
System.out: transactionY:0.0

1.2 MotionEvent和TouchSlop

MotionEvent处理一些手指在屏幕上产生的事件,如

MotionEvent.ACTION_DOWN,手指按下。

MotionEvent.ACTION_MOVE,手指在屏幕上滑动。

MotionEvent.ACTION_UP,手指松开。

MotionEvent可以监听我们手指产生事件的同时,还可以得到点击事件位置的x和y的坐标。

int x= (int) event.getX();
int y= (int) event.getY();
int rawX=(int)event.getRawX();
int rawY= (int) event.getRawY();

getx/getY和getRawX/getRawY有很大的不同。
getx/getY得到的是点击事件的位置相对于这个View左上角的x,y坐标。
getRawX/getRawY得到的是点击事件的位置相对于手机屏幕左上角的x,y坐标。手机屏幕的x,y为(0,0)

TouchSlop是系统能够识别的可以被滑动的最小距离,如果你滑动的记录小于这个值,那么将不会进行滑动。会认为你滑动距离太短。

它的作用就是,在处理滑动的时候,可以进行对滑动距离的过滤。

得到系统认为的最小滑动距离:
int mTouchSlop=ViewConfiguration.get(getContext()).getScaledTouchSlop();

1.3 VelocityTracker,GestureDetector,Scroller

VelocityTracker的例子:

public boolean onTouchEvent(MotionEvent event) {
        if (velocityTracker==null){
            //创建VelocityTracker对象
            velocityTracker = VelocityTracker.obtain();
        }
        //在onTouchEvent方法中追踪当前MotionEvent事件的速度
        velocityTracker.addMovement(event);

        //units的单位是毫秒,表示在多少毫秒内来计算的速度。假如你在50毫秒内完成了滑动,那么将计算不出来速度。
        velocityTracker.computeCurrentVelocity(100);
        /*
            computeCurrentVelocity另一个重载方法computeCurrentVelocity(int units, float maxVelocity)
            maxVelocity表示最大速率,如果速度大于了maxVelocity,显示的速度为maxVelocity。如果小于的话,那么就显示正常的速度。
            velocityTracker.computeCurrentVelocity(1000, (float)20);
        */
        xVelocity = (int) velocityTracker.getXVelocity();
        yVelocity = (int) velocityTracker.getYVelocity();

        /*
            ACTION_DOWN和ACTION_UP的事件速度一般都为0,真正需要考虑的是ACTION_MOVE时的速度。
            怎么计算速度?
                速度=(终点位置-起点位置)/规定的毫秒值

            本例中规定的毫秒值的是100毫秒。
            从左往右滑动,
                    滑动的方向和x的正方向相同,那么x方向上的速度就为正值
                        如果向下倾斜,与y的正方向相同,那么y方向的速度为正值。
            (android中的正方向是水平向右和垂直向下。)
        */
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                System.out.println("ACTION_DOWN");
                System.out.println("xVelocity:" + xVelocity);
                System.out.println("yVelocity:" + yVelocity);
                break;
            case MotionEvent.ACTION_MOVE:
                System.out.println("ACTION_MOVE");
                System.out.println("xVelocity:" + xVelocity);
                System.out.println("yVelocity:" + yVelocity);
                break;
            case MotionEvent.ACTION_UP:
                System.out.println("ACTION_UP");
                System.out.println("xVelocity:" + xVelocity);
                System.out.println("yVelocity:" + yVelocity);
                break;
        }
        return true;
    }
//当不需要使用VelocityTracker时重置并回收内存
velocityTracker.clear();
velocityTracker.recycle();

GestureDetector:

    private MyGestureDetectorListener listener;
    private GestureDetector detector;

    private void init() {
        //创建GestureDetector对象并实现OnGestureListener接口
        listener = new MyGestureDetectorListener();
        detector = new GestureDetector(listener);
    }

    /*
        轻轻触碰屏幕并抬起
                onDown---->onSingleTapUp

        长按屏幕后抬起
                onDown---->onShowPress---->onLongPress

        手指在屏幕上滑动,最后松开
                onDown---->onScroll(很多次调用)---->onFling
    */

    class MyGestureDetectorListener implements GestureDetector.OnGestureListener{
        //手指轻轻触碰屏幕触发一瞬间调用
        @Override
        public boolean onDown(MotionEvent e) {
            System.out.println("onDown");
            return true;
        }

        //手指轻轻触碰屏幕,但并没有松开或拖动
        @Override
        public void onShowPress(MotionEvent e) {
            System.out.println("onShowPress");
        }

        //手指轻轻触碰屏幕,松开。表示单击行为
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            System.out.println("onSingleTapUp");
            return true;
        }

        //手指在按下并滑动
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            System.out.println("onScroll");
            return true;
        }

        //手指长按
        @Override
        public void onLongPress(MotionEvent e) {
            System.out.println("onLongPress");
        }

        //手指按下屏幕快速滑动后松开
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            System.out.println("onFling");
            System.out.println("velocityX"+velocityX);
            System.out.println("velocityY"+velocityY);
            return true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //接管View的onTouchEvent方法
        return detector.onTouchEvent(event);
    }

Scroller:

弹性滑动对象,scroolTo和scroolBy两种方法的滑动都是瞬间完成的,没有过渡的滑动效果在。
而Scroller可以完成这个过渡效果。
它本身无法让View弹性滑动,它需要和View的computeScroll方法配合才能完成这个功能。
如何使用Scroller?会在下面介绍scroolTo和scroolBy时通过一个侧滑的demo来使用Scroller。

二,View的滑动

2.1 使用scrollTo和scrollBy

首先看源码:

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();
        }
    }
}

public void scrollBy(int x, int y) {
    scrollTo(mScrollX + x, mScrollY + y);
}

可以看出scrollBy实际上也是调用了scrollTo的方法。
并且在mScrollX ,mScrollY的基础上进行了移动。
scrollBy是绝对移动,它移动时会在上一个的位置上继续移动,而scrollTo却不是,它是直接移动到那个位置。

那么mScrollX和mScrollY是什么?
public final int getScrollX() {
       return mScrollX;
}

public final int getScrollY() {
       return mScrollY;
}
在view中可以通过getScrollX和getScrollY来获得。

mScrollX的值等于View的上边缘在水平方向上的值减去View内容的上边缘在水平方向上的值。
同理mScrollY的值等于View的下边缘在竖直方向上的值减去View内容的下边缘在竖直方向上的值。
单位是像素。
什么是View边缘,什么又是View内容的边缘?
View边缘指的是View的位置,由四个顶点组成,而View内容边缘指的是View中内容的边缘。
而scrollTo和scrollBy实现滑动,只能将View的内容进行移动。

一个概念的了解:
android的View视图是没有边界的,也就是说,我们在手机屏幕上看到的,是因为屏幕的限制,我们只能看到这么大。
既然这是前提,下面举例子来看。
public class MainActivity extends AppCompatActivity {

    private ManualView manual;//自定义的TextView

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        manual = (ManualView) findViewById(R.id.manual);
        int scrollX = manual.getScrollX();
        int scrollY = manual.getScrollY();
        System.out.println("默认情况下"+"ScrollX:"+scrollX + " --- ScrollY:" + scrollY);

        findViewById(R.id.btn_scrollby).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                manual.scrollBy(-20, 0);
                int scrollX = manual.getScrollX();
                int scrollY = manual.getScrollY();
                System.out.println("scrollby移动后" + "ScrollX:" + scrollX + " --- ScrollY:" + scrollY);
            }
        });

        findViewById(R.id.btn_scrollto).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                manual.scrollTo(100,0);
                int scrollX = manual.getScrollX();
                int scrollY = manual.getScrollY();
                System.out.println("scrollto移动后" + "ScrollX:" + scrollX + " --- ScrollY:" + scrollY);
            }
        });
    }
}

运行后:

当scrollBy(-20, 0)后,就成为了下面这个样子:

前面提到的说每一个View的视图是没有边界的,而只是因为视图的边界超过了它的父容器(可以认为是被隐藏或覆盖),所以只会显示我们眼中看到的布局视图。

这个View没有边界的视图应该是下面这样子:

当我们scrollBy(-20,0)时,内容向右移动,滚动时不是以(0,0)作为参照,是调用scrollBy以及scrollTo方法的View自己作为参照。

为什么是向右,要知道View的布局并没有移动,移动的只是View的内容。

View布局的左上减去View内容的左上,此时此刻就是-20。

按照上面所说的View边缘和View内容边缘的值的差,可以得出此时的mScrollX为-20。

有时候在想scrollTo和scrollBy移动的只是View的内容,那么有的控件没有内容,又是怎么实现这个方法的呢?

2.2 使用动画完成滑动

使用平移动画或者属性动画。动画以后再深究。

2.3 改变布局参数

通过设置控件的LayoutParams,改变Margin值来达到View的移动。
貌似这种方法也想的出来啊。

RelativeLayout.LayoutParams params=
            (RelativeLayout.LayoutParams) manual.getLayoutParams();
params.leftMargin+=100;
manual.setLayoutParams(params);
//或
manual.requestLayout();

2.4 各种滑动方法的对比

scrollTo和scrollBy方法可以很方便的实现滑动功能,但缺点是只能滑动View的内容,不可以滑动View本身。

使用动画的话,要注意属性动画只能使用到Android3.0以上,如果要向下兼容,还需要使用第三方的库。

改变布局参数,操作有些复杂,适用于有交互的View。
时间: 2024-10-09 10:16:45

View的基本概念了解的相关文章

Android View, Window,Activity概念区分(2)

(1)View:最基本的UI组件,表示屏幕上的一个矩形区域. (2)Window: 表示一个窗口,不一定有屏幕那么大,可以很大也可以很小:它包含一个View tree和窗口的layout 参数.View tree的root View可以通过getDecorView得到.还可以设置Window的Content View. (3)Activity:Activity包含一个Window,该Window在Activity的attach方法中通过调用PolicyManager.makeNewWindo创建

MVC 基本概念

1. M(Model-模型): 数据模型. 负责定义信息格式与信息反问的界面,包括商业逻辑,数据反问.(可以理解成是三层模式中的 BLL+DAL ) 2. V(View-视图): 负责用户界面 UI 的展示,网页展示的HTML代码. 3. C(Controller-控制器):负责控制系统运行的流程,跟浏览器如何交互,响应客户端各种要求.等等(就是model 与 view 之前的桥梁) 1.2 --初探MVC架构 1.2.1 Controller与View 的关联 Controller与View

【Android 初学】2、View初步

1.View的基本概念 View就是所有控件类的父类.(文本.按钮.多选.布局.··· ···) 2.在Activity当中获取代表View的对象 使用findViewById(R.id.ppp) ;ppp表示控件的ID 例如TextView textView= (TextView)findViewById(R.id.textView); 该方法将返回一个View类型,必须使用向下转型为响应的控件. 3.设置View的属性 使用上一个textView的对象: 可以修改该控件的text属性,如:t

View初步(一)

在此之前装上第三方Android设备模拟器Genymobile, 自带的太慢了..... 过程如下:http://www.cnblogs.com/iMirror/p/3768533.html 1. View的基本概念 2. 在Activity当中获取代表View的对象 3. 设置View的属性 4. 为View设置监听器 1. View的基本概念 在Activity上显示的所有控件就叫View, 都是用对象表示的, 生成对象的类都是View的子类 View是所有控件类的父类 2. 在Activi

Hibernate 优化技术之调用视图(View)和存储过程(Procedure)

前言 上一篇blog记录了hibernate抓取策略的相关用法(http://blog.csdn.net/wlwlwlwl015/article/details/42705585),它主要是在对象导航时为我们进行HQL方面的优化.本篇blog将介绍一些通用性的优化方式,即在hibernate中使用视图和存储过程.在数据量比较大时(百万级),使用hibernate时不再推荐使用HQL,而是使用原生的SQL语句,而视图.索引.存储过程等数据库对象也都是基于底层数据库和原生的SQL派生出的优化方案,废

Android(java)学习笔记95:Android原理揭秘系列之View、ViewGroup

作过Android 应用开发的朋友都知道,Android的UI界面都是由View和ViewGroup及其派生类组合而成的.其中,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的.AndroidUI界面的一般结构可参见下面的示意图: 可见,作为容器的ViewGroup可以包含作为叶子节点的View,也可以包含作为更低层次的子ViewGroup,而子ViewGroup又可以包含下一层的叶子节点的View和ViewGroup.事实上,这种灵活的Vi

ClearCase一些概念整理

基本概念 ClearCase有时候缩写为CC. 它是IBM Rational 出品的大型商用软件配置管理工具.其核心是版本控制. 尽管能够听到对ClearCase的很多抱怨,比如昂贵.复杂.不好用,但它仍然是收费的版本控制系统中市场份额最大的. 它有两个版本:Base ClearCase和ClearCase UCM. Base ClearCase向你提供的是文件.目录.版本.标签.分支.触发器和链接等"裸露"的环境. 在此基础上,你可以比较自由的进行设置和二次开发,以满足你实际项目的需

android开发之路01

一.android系统被分为4个层次:1.最下层的是linux核心,包括多个驱动程序,提供了操作系统应该具备的核心功能:2.在linux核心之上,包括两个部分,一部分是Android Runtime(包括Dalvik虚拟机,和Core Libraries相当于java中的jdk)和LIBRARIES:3.是Application Framework这一层,该层包括多个Android开发框架(即各种管理器,如资源管理器等):4.Aplication层(该层既是我们工作的领域app)二.基于组件的应

Android面试通过一个控件展示自己水平

说好的博客,终于要来了. 这篇文章写一下面试时我自己一般是如何展示自己技术水平的. 我是一名做Android的攻城狮,自己的面试经验还算不错,作为求职者自己的面试成功率比较高,而技术关我从来还没遇到不通过的.我面试的时候喜欢先自己展现下自己的技术,然后再是面试官提问:这样让面试官能全面充分的了解我的技术层次,接下来谈薪水待遇自己的话语权就会多一些. 首先声明一点:我不喜欢在面试的时候多谈业务逻辑.多谈项目经验.多去展示自己对具体Api的记忆之类的行为.因为你所谈的项目和业务逻辑,都是需要和别人配