关闭

View位置参数与滑动全解析

标签: android开发学习笔记view滑动view坐标
1149人阅读 评论(2) 收藏 举报
分类:

一. View位置参数与坐标分析

View是Android中所有控件的基类,是一种界面层的控件的一种抽象,代表一个控件,常见的获取位置参数的方法有以下三种:

1.View的getTop(),getLeft(), getRight(),getBottom()

View的位置主要由它的四个顶点来决定,分别对应View的四个属性:top,left,right,bottom,其中top是左上角纵坐标 ,left是左上角横坐标,right是右下角横坐标,bottom是右下角纵坐标。需要注意的是,这些坐标都是相对于View的父容器来说的,因此它是一种相对坐标。具体参数看下图:

这里写图片描述

在Android中,坐标系的原点在屏幕的左上角(不包括状态栏与标题栏的部分),x轴和y轴的正方向分别为向右和向下,这一点很重要。

这里写图片描述

线性布局竖直排列,从上到下依次为一个Button,一个包括TextView的线性布局,宽度,高度,边距的设置如图所示。看看在Activity中怎么获取它的位置参数:


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

    }

    private void initView() {
        mainBtn = (Button) findViewById(R.id.main_btn);
        WindowManager windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        int width = windowManager.getDefaultDisplay().getWidth();
        int height = windowManager.getDefaultDisplay().getHeight();
        Log.e("log", "屏幕宽度:" + width);
        Log.e("log", "屏幕高度:" + height);

    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        Log.e("log", "按钮的getTop():" + mainBtn.getTop());
        Log.e("log", "按钮的getBottom():" + mainBtn.getBottom());
        Log.e("log", "按钮的getLeft():" + mainBtn.getLeft());
        Log.e("log", "按钮的getRight():" + mainBtn.getRight());

        Log.e("log", "按钮的getWidth(px):" + mainBtn.getWidth());
        Log.e("log", "按钮的getHeight(px):" + mainBtn.getHeight());

        Log.e("log", "按钮的getWidth(dp):" + px2dp(getApplicationContext(), mainBtn.getWidth()));
        Log.e("log", "按钮的getHeight(dp):" + px2dp(getApplicationContext(), mainBtn.getHeight()));

        Log.e("log", "文字的getTop():" + mainTxt.getTop());
        Log.e("log", "文字的getBottom():" + mainTxt.getBottom());
        Log.e("log", "文字的getLeft():" + mainTxt.getLeft());
        Log.e("log", "文字的getRight():" + mainTxt.getRight());
    }

    //px转dp
    public static int px2dp(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

获取屏幕的高度与宽度,然后重写Activity的onWindowFocusChanged方法,获取View的位置参数。刚开始我把这些方法直接写在onCreate中,获取到的值都是0。后来才知道,width、height、top、left等属性值是在Measure与Layout过程完成之后才开始正确赋值的,而Measure与Layout都晚于onCreate方法执行,所以onCreate中根本就取不到值!

关于正确获取组件的宽高,可参考以下这篇博文:

http://blog.csdn.net/qq_23547831/article/details/51764304

我们一起看一下测试结果:

这里写图片描述

这里的单位默认都是px,从以上结果我们可以得到以下结论:

View的位置参数是相对于自身的父容器来说的,是相对坐标可以看到测试文字的坐标参数是相对于自己的父容器计算的。

View的宽高与坐标的关系:

width = right - left
height = bottom - top

最后我将得到的宽高单位从(px)转换成了(dp),可以看到大小与我们在xml中设置的一致,完美~

2.View的getLocationInWindow()

这个方法获取的是View在当前窗口的绝对坐标,看一下测试代码:

            int[] btnWindowInt = new int[2];
            mainTxt.getLocationInWindow(btnWindowInt);
            Log.e("log", "文字在当前窗口内的绝对横坐标:" + btnWindowInt[0]);
            Log.e("log", "文字在当前窗口内的绝对纵坐标:" + btnWindowInt[1]);


            int[] llWindowInt = new int[2];
            maniLinearLayout.getLocationInWindow(llWindowInt);
            Log.e("log", "线性布局在当前窗口内的绝对横坐标:" + llWindowInt[0]);
            Log.e("log", "线性布局在当前窗口内的绝对纵坐标:" + llWindowInt[1]);

测试结果:

这里写图片描述

打印结果里的线性布局就是父线性布局。可以看到,这个线性布局的绝对纵坐标包括了通知栏与状态栏的高度,我们在实际项目运用这个方法的过程中,一定记得减去这个高度。因为Android坐标系的原点在屏幕的左上角(不包括状态栏与标题栏的部分)。

3.MotionEvent的getX(),getY(),getRawX(),getRawY()

首先理解这四个参数的意义:

getX():获取点击事件相对控件左边的x轴坐标,即点击事件距离控件左边的距离
getY():获取点击事件相对控件顶边的y轴坐标,即点击事件距离控件顶边的距离
getRawX():获取点击事件相对整个屏幕左边的x轴坐标,即点击事件距离整个屏幕左边的距离
getRawY():获取点击事件相对整个屏幕顶边的y轴坐标,即点击事件距离整个屏幕顶边的距离

测试代码:

还是之前的布局,我们给测试文字添加一个触摸监听:

       mainTxt.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {

                int x = (int) event.getX();
                int y = (int) event.getY();
                int xRaw = (int) event.getRawX();
                int yRaw = (int) event.getRawY();
                switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN:
                        Log.e("log", "触摸事件相对控件坐标为:" + x + "," + y);
                        Log.e("log", "触摸事件相对屏幕坐标为:" + xRaw + "," + yRaw);

                        break;
                    case MotionEvent.ACTION_MOVE:

                        break;
                    case MotionEvent.ACTION_UP:

                        break;
                }
                return false;
            }
        });

然后点击测试文字,看一下打印的结果:

这里写图片描述

那么这种结果在可以滑动的控件中是怎样的呢,比如ListView,RecyclerView。其实对于这种滑动的ViewGroup,我们在获取ViewGroup的坐标值时并不需要考虑它到底滑动了多少(实际滑动的我们应该看作是ViewGroup中的View在滑动)。获取到的结果与这里还是一样的,具体应用案例可参考我之前一篇博客:

http://blog.csdn.net/tyk0910/article/details/51669205

二. View的最小滑动距离

TouchSlop是系统所能识别出的最小的滑动距离,如果两次滑动之间的距离小于这个常量,那么系统就不认为你是在进行滑动操作。

ViewConfiguration.get(getApplicationContext()).getScaledTouchSlop();

可通过以上方法获取到这个常量,打印出来大小是8dp。当我们处理滑动时,可以利用这个常量来做一些过滤,比如当两次滑动事件的距离小于这个值,我们就可以认为没有达到滑动距离的临界值,因此可以认为它们不是滑动的。这样做可以有更好的用户体验。

三.View滑动全解析

目前Android中实现View的滑动可以分为三种方式:

通过改变View的布局参数使得View重新布局从而实现滑动

通过scrollTo/scrollBy方法来实现View的滑动

通过动画给View施加平移效果来实现滑动

这里将一一解析这三种方式的用法与区别:

首先看一下我们测试的布局文件

这里写图片描述

然后就是Activity里的代码:

    private void init() {
        testBtn = (Button) findViewById(R.id.second_btn);
        textView = (TextView) findViewById(R.id.second_txt);
        testBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {


                Log.e("log", "测试文字的getTop():" + textView.getTop());
                Log.e("log", "测试文字的getBottom():" + textView.getBottom());
                Log.e("log", "测试文字的getLeft():" + textView.getLeft());
                Log.e("log", "测试文字的getRight():" + textView.getRight());
            }
        });

        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(getApplicationContext(), "测试文字的点击事件", Toast.LENGTH_SHORT).show();
            }
        });
    }

点击按钮的时候,滑动测试文字textView,打印textView的位置参数,并且监听textView的点击事件。

测试文字的初始位置参数如下所示:

这里写图片描述

通过添加不同的方法来滑动测试文字,并且打印位置参数。所有方法的测试结果的示例图如下:

这里写图片描述

一起看看怎么实现的:

1.通过改变View的布局参数使得View重新布局从而实现滑动

1.使用layout(int l, int t, int r, int b)方法重新布局:

textView.layout(textView.getLeft() + 50, textView.getTop() + 50, textView.getRight() + 50, textView.getBottom() + 50);

测试文字位置参数改变:

这里写图片描述

测试文字点击事件有效

2.使用offsetTopAndBottom(int offset)与offsetLeftAndRight(int offset)方法进行偏移:

textView.offsetTopAndBottom(50);
textView.offsetLeftAndRight(50);

测试文字位置参数改变:

这里写图片描述

测试文字点击事件有效

3.使用LayoutParams方法动态修改布局参数:

      LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) textView.getLayoutParams();
                layoutParams.leftMargin = textView.getLeft() + 50;
                layoutParams.topMargin = textView.getTop() + 50;
                textView.setLayoutParams(layoutParams);

测试文字位置参数不变:

这里写图片描述

测试文字点击事件有效

2.通过scrollTo/scrollBy方法来实现View的滑动

4.使用scrollTo(int x, int y)方法进行移动:

关于view的scrollTo方法,我在 RecyclerView学习(三)—-高仿知乎的侧滑删除 这篇博客中有很详细的介绍,大家也可以参考启舰大神的ListView滑动删除实现之二——scrollTo、scrollBy详解

//布局文件
    <LinearLayout
        android:id="@+id/second_ll"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/second_txt"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="@color/colorAccent"
            android:gravity="center"
            android:text="测试文字" />

    </LinearLayout>


linearLayout = (LinearLayout) findViewById(R.id.second_ll);
linearLayout.scrollTo(-50, -50);

之所以加上一个父布局,是因为scrollTo/scrollBy方法只能滑动view的内容,并不能滑动view本身。

测试文字位置参数不变:

这里写图片描述

测试文字点击事件有效

5.使用scrollBy(int x, int y)方法进行移动:

 linearLayout.scrollBy(-50, -50);

测试文字位置参数不变:

这里写图片描述

测试文字点击事件有效

3. 通过动画给View施加平移效果来实现滑动

6.使用补间动画实现view的移动:

                TranslateAnimation translateAnimation = new TranslateAnimation(0, 200, 0, 200);
                translateAnimation.setDuration(1000);
                translateAnimation.setFillAfter(true);
                textView.startAnimation(translateAnimation);

测试文字位置参数不变:

这里写图片描述

使用补间动画实现的测试文字滑动,会导致测试文字的点击事件无效,只有点击原区域,事件才会有效!!!

7.使用属性动画实现view的移动:


                AnimatorSet set = new AnimatorSet();
                set.playTogether(
                        ObjectAnimator.ofFloat(textView, "translationX", 0, 200),
                        ObjectAnimator.ofFloat(textView, "translationY", 0, 200)

                );
                set.start();

测试文字位置参数不变:

这里写图片描述

使用属性动画实现的测试文字滑动,点击事件依然有效!!!

那么综合对比这三种方式,各自的特点是什么呢:

通过改变View的布局参数使得View重新布局从而实现滑动 ,操作稍微复杂,适用于有交互的View

通过scrollTo/scrollBy方法来实现View的滑动,操作简单,适合对View内容的滑动

通过动画给View施加平移效果来实现滑动,操作简单,主要适用于没有交互的View和实现复杂的动画效果

1
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

实现view跟着手指滑动的效果(实现方式一)

实现该效果的基本思想是:当触摸view时,系统记下当前触摸点的坐标,当手指移动时,系统记下移动后的触摸点坐标,从而获取到相对于前一次坐标点的偏移量,并通过偏移量来修改view的坐标,这样不断重复,从而实现滑动的效果。 首先我们需要自定义一个view,并置于一个LinearLayout中,代码如下: ...
  • sweetzhangxue
  • sweetzhangxue
  • 2016-11-22 16:00
  • 1280

Android学习笔记-使用layout方法使View随手指的滑动而滑动

看AndroidHero 这本书时,有一个例子是关于移动View使用view的layout方法来移动,对于触摸事件的处理在这里记录一下 1.思路在View的onTouchEvent方法中对MotionEvent中的坐标进行记录,记录按下的时候记录,在移动的时候计算他们的偏移量,调用layout()对...
  • u014738387
  • u014738387
  • 2016-01-17 15:34
  • 797

Android自定义View之滑动取值条

Android自定义View之滑动取值条1 : 需求 可自定义更改滑动条的样式(本功能实现两种样式) 联动方式 : 滑块上更新的值通过回调给Edittext; 在Edittext上输入值,更新滑动条的游标的位置和值 高度复合性: 可根据需求,自初始化值,及返回值的调整,显示精度的可调整性 ,...
  • sinat_28891771
  • sinat_28891771
  • 2017-05-08 13:11
  • 1014

Android 自定义View 让内容跟随手指滚动

需求: 自定义一个View,当Canvas绘制的内容超过当前屏幕,希望能够通过手指触摸屏幕的方法移动画布的内容。 实现思路: 通过View的OnTouchEvent方法可以监听当前手指的位置,可以计算出滑动的距离,当前速度。通过View的scrollTo、scrollBy方法可以直接将画图移动到...
  • mxw3755
  • mxw3755
  • 2016-05-25 16:34
  • 806

android之ScrollView滑动到指定的View

昨天看有人问ScrollView滑动到指定的View,说实话我没做过这需求,但是一看应该很简单吧,不就是计算下需要滑动的距离然后调用下滑动方法进行滑动吗?然后他又说不行,我反正是不知道为啥了,难道我理解错了他的意思?啊哈哈,管他的,当时我还以为是我想法不对,我就去验证了下,结果呢,几行代码就搞定了,...
  • gsw333
  • gsw333
  • 2016-11-25 11:17
  • 5172

重写viewgroup现实上下view滑动(修改版)

寒假编写app时用到了上下view的切换,故把之前的代码优化了下,当然我的水平还是很有限的,在编写之前弄懂了安卓的事件机制,费了不少功夫,还好在自己实践后就很好理解了 安卓的事件是:分为分发事件和处理事件,事件是往上分发的(即向子view分发)处理事件时往下"滚"的,我的表达能...
  • u013571243
  • u013571243
  • 2015-02-27 12:20
  • 714

View的滑动之瞬间滑动与弹性滑动

View的滑动之瞬间滑动与弹性滑动
  • qq_24530405
  • qq_24530405
  • 2016-01-19 15:53
  • 1148

Android View体系(二)实现View滑动的六种方法

View的滑动是Android实现自定义控件的基础,同时在开发中我们也难免会遇到View的滑动的处理。其实不管是那种滑动的方式基本思想都是类似的:当触摸事件传到View时,系统记下触摸点的坐标,手指移动时系统记下移动后的触摸的坐标并算出偏移量,并通过偏移量来修改View的坐标。
  • itachi85
  • itachi85
  • 2016-02-28 17:19
  • 14047

android view 上下左右滑动 事件

import android.app.Activity; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; impo...
  • yhqbsand
  • yhqbsand
  • 2014-04-02 15:54
  • 13275

Android——View的事件体系(一)View的滑动

主要介绍内容: View的基础知识 View的位置参数 MotionEvent 和 TouchSlope VelocityTracker、GestureDetector 和 Scroller View的滑动 使用scrollTo/scrollBy 使用动画 改变布局参数 各种滑动方式的对比 弹性...
  • AkaiC
  • AkaiC
  • 2016-09-26 00:10
  • 1300