Android 自定义View:实现View的滑动效果
来源:互联网 发布:js如何获取当前时间 编辑:程序博客网 时间:2024/05/14 03:26
相关文章:
Android坐标系分析
Android自定义View 之 View的测量
Android 自定义View之View的绘制
之前学习了View的测量和绘制,我们已经可以定制自己喜欢外观的View了
今天再来学习一下如何定制View的滑动效果。
View的滑动效果,本质上就是通过改变View的坐标来实现的。
关于Android 坐标系,之前我也写过文章特意讲了,我们再简单巩固一下。
坐标系分两种
一种是绝对坐标系,就是以手机屏幕左上角为原点。
View.getLocationOnScreen(int[] location) 还有 MotionEvent.getRawX()、MotionEvent.getRawY() 都是以这个坐标系为基准获取的坐标
我们称之为 绝对坐标
一种是视图坐标系,就是以父视图左上角为坐标原点
View.getLeft()等是以父布局为基准,
View.getLocationInWindow(int[] location)以父窗体为基准,
Canvas绘制和MotionEvent.getX()等是以当前View(父视图)为基准的
通常我们移动View,都和手指在屏幕上的触碰,拖动离不开关系
那么,如何捕捉到手指的触控呢?
这就要用到View的onTouchEvent(MotionEvent event)方法啦
public class MyView extends View{public MyView(Context context) {super(context);// TODO Auto-generated constructor stub}@Overridepublic boolean onTouchEvent(MotionEvent event){return true;}}onTouchEvent只有return true 这个事件的处理才会生效
而我们如何分辨传来的MotionEvent是什么类型呢?
这就要用到MotionEvent封装的事件常量,常用的有以下几种
通过这些事件常量,我们就可以定位到相应的事件,做相应的处理
通常我们onTouchEvent这个方法会以下面模式重写
@Overridepublic boolean onTouchEvent(MotionEvent event){switch(event.getAction()){case MotionEvent.ACTION_DOWN://检测到手指触碰屏幕//写相关的事件//比如,获得触点的x视图坐标int x = (int)event.getX();break;case MotionEvent.ACTION_MOVE://手指在屏幕上滑动break;case MotionEvent.ACTION_UP://手指离开屏幕break;}return true;}当然,你也可以用if来判断,只是架构不如switch清晰
此外,你也可以通过case分支检测其他的触摸事件并处理
实现滑动的七种方法
1.layout方法
View在进行绘制时,会调用onLayout()方法来设置当前显示的位置,最终通过调用layout(left,top,right,bottom)设置View左上右下顶点的坐标来设置位置
(为什么四个点就可以?因为View本身是矩形)
下面的代码,我们就通过这个方法的运用,来实现一个被手指拖动的小球。
public class MyView extends View{//设置wrap_content时候View的大小private int defaultWidth = 100;private int defaultHeight = 100;//画笔 用于画圆private Paint p = new Paint();//View当前的位置private int rawX = 0;private int rawY = 0;//View之前的位置private int lastX = 0;private int lastY = 0;public MyView(Context context){super(context);}public MyView(Context context, AttributeSet set) {super(context, set);}//画一个红色,圆心为View中心点,半径为View宽度的圆public void onDraw(Canvas canvas){//Log.e("onDraw执行","true");p.setColor(Color.RED);int x = this.getLeft() + this.getWidth()/2;int y = this.getTop() + this.getHeight()/2;canvas.drawCircle(this.getWidth()/2, this.getHeight()/2, this.getWidth()/2, p);}//注意,触摸事件的响应范围仅限于该View的区域public boolean onTouchEvent(MotionEvent event){//Log.e("onTouchEvent执行","true");switch(event.getAction()){case MotionEvent.ACTION_DOWN://Log.e("ACTION","down");//获取手指落下的坐标并保存rawX = (int)(event.getRawX());rawY = (int)(event.getRawY());lastX = rawX;lastY = rawY;break;case MotionEvent.ACTION_MOVE://Log.e("ACTION","move");//手指拖动时,获得当前位置rawX = (int)event.getRawX();rawY = (int)event.getRawY();//手指移动的x轴和y轴偏移量分别为当前坐标-上次坐标int offsetX = rawX - lastX;int offsetY = rawY - lastY;//通过View.layout来设置左上右下坐标位置//获得当前的left等坐标并加上相应偏移量layout(getLeft() + offsetX,getTop() + offsetY,getRight() + offsetX,getBottom() + offsetY);//移动过后,更新lastX与lastYlastX = rawX;lastY = rawY;break;}return true;}//简单的重写onMeasureprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){setMeasuredDimension(defaultWidth,defaultHeight);}else if(widthSpecMode == MeasureSpec.AT_MOST){setMeasuredDimension(defaultWidth,heightSpecSize);}else if(heightSpecMode == MeasureSpec.AT_MOST){setMeasuredDimension(widthSpecSize, defaultHeight);}else{setMeasuredDimension(widthSpecSize, heightSpecSize);}}}引用MyView的布局文件
<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" tools:context="com.example.androidslide.MainActivity" > <com.example.androidslide.MyView android:background="#00ffff" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <!-- 我们给View设置一个蓝色的背景,方便比较View的区域和我们绘制的圆的区域 --></RelativeLayout>
逻辑并不复杂,大家结合注释自己理解实验一下
2.offsetLeftAndRight() 与 offsetTopAndBottom()
这两个也是View自带的方法,根据方法名也很容易看出来操作对象是 左右,上下
因为左右移动是x轴移动,上下移动是y轴移动
结合上一部分layout的代码,我们只需稍作修改就可以
offsetLeftAndRight(offsetX);offsetTopAndBottom(offsetY);
大家自己实践一下
3.LayoutParams
因为View一定是在一个布局中,而且View的位置常常是由父布局来定的
LayoutParams保存了一个View的布局参数,所以我们可以通过改变LayoutParams来改变View的位置达到移动的效果
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)getLayoutParams();layoutParams.leftMargin = getLeft() + offsetX;layoutParams.topMargin = getTop() + offsetY;setLayoutParams(layoutParams);
也可以通过具体的父布局,比如 LinearLayout.LayoutParams 或者 RelativeLayout.LayoutParams 来实现。
4. scrollTo 与 scrollBy(等写完ViewGroup的自定义再讲)
5.Scroller(和scrollTo 和 scrollBy一起讲)
6.属性动画(单独作为一篇文章总结动画)
7.ViewDragHelper(要用到事件拦截机制,写完事件分发和拦截文章再讲)
对了,大家看完上述例子,千万不要以为,移动小球坐标都一定要在onTouchEvent内写。
你甚至可以在activity中,通过子线程不断更新UI线程来不断移动View实现跑马灯的效果
多尝试尝试,有问题欢迎留言~
通过layout方法实现滑动的小球的源码 点击打开链接
- Android 自定义View:实现View的滑动效果
- Android 自定义View:实现View的滑动效果
- android自定义view实现progressbar的效果
- Android view滑动悬浮固定效果实现
- 滑动效果的View
- Android 自定义View 实现垂直滑动页
- android 自定义view实现可左右滑动的Tabbar
- android:滑动挂断自定义View的简单实现
- Android 自定义view的实现 滑动按钮案列
- Android之自定义View实现随手势滑动的控件
- Android自定义View,实现全屏滑动的DrawerLayout
- Android自定义动态的View,实现飘雪的效果
- android 实现 view 滑动
- Android自定义View你所要知道的(三):View滑动实现方式
- Android 自定义view实现水波纹效果
- Android 自定义View 实现刮刮卡效果
- Android:自定义View实现水波进度效果
- android 自定义view实现水波纹效果
- mysql 中主键和索引的关系和说明
- STL map的遍历与pair的使用
- DayDayUP_Python自学记录[2]_Python变量类型
- 我是SB
- 高校云平台(五):移动开发之环境搭建
- Android 自定义View:实现View的滑动效果
- Notification的使用
- hdu 1753 大明A+B 长小数相加
- Android Studio引用Library与导入jar
- js获取浏览器高度和宽度值(多浏览器)
- .NET实验7-1
- React Native 开发(第一篇)
- 服务器端Json生成及Android客户端的json解析
- ZOJ 3946 Highway Project SPFA 两个限制条件