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向右滑动而且变胖了,但是瞬间滑动过去的,没有动画效果
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向右滑动而且变胖了,但是瞬间滑动过去的,没有动画效果
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories