您的位置:首页 > 移动开发 > Android开发

android 自定义控件学习之三 控件布局常用知识总结

2016-06-03 11:21 435 查看

1、View是什么

View是Android所有控件的基类,简单到TextView、Button,复杂到RelativeLayout,LinearLayout,其共同基类都是View。

所以,View可以理解为控件的抽象,也是一个控件。

除此之外,还有ViewGroup,字面意义上,它表示控件组,内部可以包含许多个控件。

ViewGroup也继承自View,这意味着,一个View的可以是单个控件,也可以是多个控件组成的一组控件,这就形成了View树。

下面这个图很好地体现了View的继承关系



2、View的相关参数

View的位置决定于它的四个顶点,对应View的四个属性:

Top:左上角纵坐标,通过getTop ()获得

Left:左上角横坐标,通过getLeft()获得

Right: 右下角横坐标,通过getRight ()获得

Bottom: 右下角纵坐标,通过getBottom ()获得

这些坐标都是相对于View的父容器所说的,是一种相对坐标。

下面这张图表示的是View中涉及位置参数的各个方法对应的具体含义。

最外层是手机屏幕,中间是一个ViewGroup嵌套一个View。

涉及到的其他方法请继续往下看。



此外,参数x,y表示View左上角的横纵坐标,

translationX和translationY表示View的左上角相对于父容器的偏移量。

他们都有相应的Get/Set方法

这几个参数也是相对于父容器的坐标

可以知道,这几个参数换算关系如下

x = left + translationX

y = top + translationY

利用这些参数,我们来自定义一个能随手指滑动而改变位置的View

实现如下效果:

初始位置:



手指滑动后,自定义View走到了图示位置:



代码如下:

自定义View

[java] view
plain copy

 





public class DragView extends View{  

  

    int lastX;  

    int lastY;  

  

    public DragView(Context context) {  

        super(context);  

    }  

  

    public DragView(Context context, AttributeSet attrs) {  

        super(context, attrs);  

    }  

  

    @Override  

    protected void onDraw(Canvas canvas) {  

        super.onDraw(canvas);  

    }  

  

    @Override  

    public boolean onTouchEvent(MotionEvent event) {  

  

        int x = (int) event.getX();  

        int y = (int) event.getY();  

        Log.e("触发onTouchEvent",x+"::::::"+y);  

  

        switch (event.getAction()){  

            case MotionEvent.ACTION_DOWN:{  

                lastX = x;  

                lastY = y;  

            }  

            break;  

            case MotionEvent.ACTION_MOVE:{  

                int offsetX = x - lastX;  

                int offsetY = y - lastY;  

                Log.e("触发ACTION_MOVE",offsetX+"::::::"+offsetY);  

                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);  

                Log.d("DragView",getLeft()+"______"+getTop()+"-------"+getBottom()+"-------"+getRight());  

            }  

            break;  

        }  

  

        return true;  

    }  

}  

布局:

[html] view
plain copy

 





<RelativeLayout  

    xmlns:android="http://schemas.android.com/apk/res/android"  

    xmlns:tools="http://schemas.android.com/tools"  

    android:layout_width="match_parent"  

    android:layout_height="match_parent"  

    android:paddingBottom="@dimen/activity_vertical_margin"  

    android:paddingLeft="@dimen/activity_horizontal_margin"  

    android:paddingRight="@dimen/activity_horizontal_margin"  

    android:paddingTop="@dimen/activity_vertical_margin"  

    tools:context="com.lian.scrolltest.MainActivity">  

  

    <com.lian.scrolltest.DragView  

        android:layout_width="100dp"  

        android:layout_height="100dp"  

        android:background="#000000"  

  

        />  

</RelativeLayout>  

MainActivity直接显示布局即可

很好地实现了如上效果

3、MotionEvent和TouchSlop

(1)MotionEvent

我们在自定义View的时候,常常需要在onTouchEvent()中定义触摸行为

典型的触摸事件类型包括:

ACTION_DOWN:手指刚刚接触屏幕

ACTION_MOVE:手指在屏幕上移动

ACTION_UP:手指从屏幕离开

通过MotionEvent对象,我们可以得到点击事件的一系列位置参数

getX(),getY():触摸事件发生的位置相对于View的坐标

getRawX(),getRawY()返回返回相对于屏幕左上角的x 和 y 坐标

(2)TouchSlop

表示系统能辨识出的认为是滑动的最小距离。

若两次滑动小于此常量,判定为不属于滑动操作

这个常量的大小和手机有关。

通过如下方式获得:

[java] view
plain copy

 





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

我们处理滑动事件时,可以用这个参数进行过滤。

4、VelocityTracker、GestureDetector、Scroller

(1)VelocityTracker

用于追踪滑动过程中的速度,包括水平和竖直方向的速度。

使用方法:

在View的onTouchEvent()中将Event托管给VelocityTracker,

采用相应API获取参数

[java] view
plain copy

 





//获取对象  

VelocityTracker velocityTracker = VelocityTracker.obtain();  

//托管event  

velocityTracker.addMovement(event);  

//设置时间间隔,结果会表示为每1000毫秒经过多少像素,若设置为100,结果表示为没100毫秒经过多少像素  

velocityTracker.computeCurrentVelocity(1000);  

//获取X和Y方向上的速度  

int xVelicity = (int) velocityTracker.getXVelocity();  

int yVelicity = (int) velocityTracker.getYVelocity();  

比如1秒内X方向滑动了100像素,那么参数设置为1000时,结果就为100,表示1000毫秒划过100像素

参数设置为100时,结果就为10(表示每100毫秒划过10像素)

不需要使用时,对其进行回收

[java] view
plain copy

 





velocityTracker.clear();  

velocityTracker.recycle();  

(2)GestureDetector

GestureDetector中将封装了一系列触摸行为,包括单击、滑动、长按,双击等。

使用:

在自定义View中实现onGestureDetector接口,在其中重写onSingleTapTop()-单击事件、onFiling()-快速滑动、omLongPress()-长按、onDoubleTap()-双击

等方法,定义自己的事件处理逻辑

还有,在onTouchEvent()中:

[java] view
plain copy

 





//获取对象  

GestureDetector gestureDetector = new GestureDetector(this);  

//解决长按屏幕后无法拖动的问题  

gestureDetector.setIsLongpressEnabled(false);  

//托管event  

boolean consume = gestureDetector.onTouchEvent(event);  

return consume;  

(3)Scroller

用于实现View的弹性滑动。

为了让View实现滑动,我们常常使用scrollTo和ScrollBy,但其过程是瞬间完成的,没有过度效果,用户体验并不好。

使用Scroller和View的computeScroll配合,可以实现有过渡效果的滑动

三、View的滑动

滑动是自定义View使用最多的效果之一,

有三种实现方式:

a、View的scrollTo/ScrollBy方法

b、使用动画为View施加平移效果

c、改变View的LayoutParams是的View重新布局实现滑动

1、使用scrollTo/ScrollBy

源码:

[java] view
plain copy

 





/** 

 * 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) {  

    scrollTo(mScrollX + x, mScrollY + y);  

}  

scrollBy实际上也调用scrollTo方法,实现基于当前位置的滑动,scrollTo实现基于所传递参数的绝对滑动

mScrollX和mScrollY可以动过get方法得到。

mScrollX的值总是等于View的左边缘到View的内容左边缘水平方向的距离,

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

需要注意的是,scrollBy和scrollTo只能改变View的内容的位置而不能改变View在布局中的位置

在View的内容位置改变是,mScrollX和mScrollY值可正可负

2、使用动画

通过动画可以让一个View进行平移,主要是操作View的translationX和translationY属性,可以用View动画,也可以用属性动画。

以属性动画为例,

我们在上面例子的基础上添加一个按钮



点击按钮,View在1秒钟的时间内向右平移200像素



通过如下代码:

[java] view
plain copy

 





Button button = (Button) findViewById(R.id.btn);  

button.setOnClickListener(new View.OnClickListener() {  

    @Override  

    public void onClick(View v) {  

        dragView.animate().translationX(200).setDuration(1000).start();  

    }  

});  

3.改变布局参数

即改变LayoutParams,

比如我们让以上自定义View向右平移100像素

只要将此View的marginLeft参数值增加100px

同样以上为例,将自定义View的宽度增加100px,向右平移100px

[java] view
plain copy

 





button.setOnClickListener(new View.OnClickListener() {  

    @Override  

    public void onClick(View v) {  

        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) dragView.getLayoutParams();  

        layoutParams.width+=100;  

        layoutParams.leftMargin+=100;  

        dragView.requestLayout();  

        //或者dragView.setLayoutParams(layoutParams);  

    }  

});  

点击按钮发现View向右滑动而且变胖了,但是瞬间滑动过去的,没有动画效果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息