自定义控件(29)---onTouchEvent与Scroller
来源:互联网 发布:httppost json参数 编辑:程序博客网 时间:2024/05/17 03:59
转自 http://blog.csdn.net/yanzhenjie1003/article/details/53046027
我们定义一个ScrollLayout,然后继承自LinearLayout,在xml中引用,然后在ScrollLayout中放一个TextView,并让内容居中:
<?xml version="1.0" encoding="utf-8"?><com.yanzhenjie.defineview.widget.ScrollLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按住我拖动试试" /></com.yanzhenjie.defineview.widget.ScrollLayout>
布局就是这样的,根据上面的分析我们实现ScrollLayout的具体代码,请看:
// 手指最后在View中的坐标。private int mLastX;private int mLastY;// 手指按下时View的相对坐标。private int mDownViewX;private int mDownViewY;@Overridepublic boolean onTouchEvent(MotionEvent event) { // 第一步,记录手指在view的坐标。 int x = (int) event.getRawX(); int y = (int) event.getRawY(); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: { // 记录View相对于初始位置的滚动坐标。 mDownViewX = getScrollX(); mDownViewY = getScrollY(); // 更新手指此时的坐标。 mLastX = x; mLastY = y; return true; } case MotionEvent.ACTION_MOVE: { // 计算手指此时的坐标和上次的坐标滑动的距离。 int dy = y - mLastY; int dx = x - mLastX; // 更新手指此时的坐标。 mLastX = x; mLastY = y; // 滑动相对距离。 scrollBy(-dx, -dy); return true; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { scrollTo(mDownViewX, mDownViewY); return true; } } return super.onTouchEvent(event);}
Scroller
Scroller是手指滑动中比较重要的一个辅助类,可以辅助我们完成一些动画参数的计算等,下面把它的几个重要的方法做个简单解释。
Scroller#startScroll(int startX, int startY, int dx, int dy)Scroller#startScroll(int startX, int startY, int dx, int dy, int duration)这俩方法几乎是一样的,用来标记一个View想要从哪里移动到哪里。startX,x方向从哪里开始移动。startY,y方向从哪里开始移动。dx,x方向移动多远。dy,y方向移动多远。duration,这个移动操作需要多少时间执行完,默认是250毫秒。
private Scroller mScroller;private int mLastX;private int mLastY; public ScrollLayout(Context context) { this(context, null, 0);}public ScrollLayout(Context context, AttributeSet attrs) { this(context, attrs, 0);}public ScrollLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mScroller = new Scroller(context);}@Overridepublic boolean onTouchEvent(MotionEvent event) { int x = (int) event.getRawX(); int y = (int) event.getRawY(); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: { if (!mScroller.isFinished()) { // 如果上次的调用没有执行完就取消。 mScroller.abortAnimation(); } mLastX = x; mLastY = y; return true; } case MotionEvent.ACTION_MOVE: { int dy = y - mLastY; int dx = x - mLastX; mLastX = x; mLastY = y; scrollBy(-dx, -dy); return true; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { // XY都从滑动的距离回去,最后一个参数是多少毫秒内执行完这个动作。 mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY(), 1000); invalidate(); return true; } } return super.onTouchEvent(event);}/** * 这个方法在调用了invalidate()后被回调。 */@Overridepublic void computeScroll() { if (mScroller.computeScrollOffset()) { // 计算新位置,并判断上一个滚动是否完成。 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate();// 再次调用computeScroll。 }}
类似ViewPager的翻页效果
content_scroll_pager.xml
<?xml version="1.0" encoding="utf-8"?><com.safly.ui.ScrollPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/content_scroll_pager" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/holo_blue_light" android:gravity="center" android:minHeight="200dp" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="第一页" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/holo_green_dark" android:gravity="center" android:minHeight="200dp" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="第二页" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/holo_orange_dark" android:gravity="center" android:minHeight="200dp" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="第三页" /> </LinearLayout></com.safly.ui.ScrollPager>
/* * Copyright © Yan Zhenjie. All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.safly.ui;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.Scroller;/** * Created by Yan Zhenjie on 2016/11/5. */public class ScrollPager extends ViewGroup { private Scroller mScroller; // 手指每次移动时需要更新xy,记录上次手指所处的坐标。 private float mLastX; public ScrollPager(Context context) { this(context, null, 0); } public ScrollPager(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ScrollPager(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mScroller = new Scroller(context); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getRawX(); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: if (!mScroller.isFinished()) { // 如果上次的调用没有执行完就取消。 mScroller.abortAnimation(); } mLastX = x; return true; case MotionEvent.ACTION_MOVE: int dxMove = (int) (mLastX - x); scrollBy(dxMove, 0); mLastX = x; return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { // 当手指抬起时,第几屏占的比例大就去第几屏。(这里在除的时候+view一半宽是因为滑动到0.6的时候,不到1,结果就是0 // 其实按照惯性应该是1,所以我们给它补上一般的屏,这样相当于4设5入。) int sonIndex = (getScrollX() + getWidth() / 2) / getWidth(); // 如果滑动页面超过当前页面数,那么把屏index定为最大页面数的index。 int childCount = getChildCount(); if (sonIndex >= childCount) sonIndex = childCount - 1; // 现在滑动的相对距离。 int dx = sonIndex * getWidth() - getScrollX(); // Y方向不变,X方向到目的地。 mScroller.startScroll(getScrollX(), 0, dx, 0, 500); invalidate(); break; } } return super.onTouchEvent(event); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int childCount = getChildCount(); // 在Layout 子view之前测量子view大小,在onLayout的时候才能调用getMeasuredWidth()和getMeasuredHeight()。 for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); measureChild(childView, widthMeasureSpec, heightMeasureSpec); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); int childW = childView.getMeasuredWidth(); // 把所有子view放在水平方向,依次排开。 // left: 0, w, 2w, 3w.. // top: 0... // right: w, 2w, 3w... // topL h... childView.layout(i * childW, 0, childW * i + childW, childView.getMeasuredHeight()); } } }}
0 0
- 自定义控件(29)---onTouchEvent与Scroller
- Android自定义控件来袭(Scroller)
- Android 自定义控件之Scroller与computeScroll的调用关系
- 解决ScrollView 与 自定义控件中的onTouchEvent 冲突问题
- 手势滑动之玩转onTouchEvent()与Scroller
- 手势滑动之玩转onTouchEvent()与Scroller
- 手势滑动之玩转onTouchEvent()与Scroller
- android自定义控件系列----Scroller类详解
- Android自定义控件热身之Scroller详解
- 【ANDROID自定义控件】可扩展的TextView,ExpandableTextView与Scroller类的使用
- 自定义控件中onInterceptTouchEvent()和onTouchEvent()用法
- android 自定义view,绘制与onTouchEvent事件(一)
- 史上最全的android用户界面scroller介绍(自定义控件必须掌握的知识)
- 自定义控件篇 第二章 输入事件(触摸滑动,Scroller,事件分发机制)
- android-自定义ViewGroup与onTouchEvent监听-随心
- 自定义控件—Scroller屏幕平缓滑动工具类
- scroller与scrollto使用(二)
- 自定义ImageView重写onTouchEvent
- Service服务之---------用服务来接收广播
- Linux服务器使用一:CentOS6.6安装与搭建流程及心得
- drawable下的圆角背景XML
- 分享Kali Linux 2016.2第48周虚拟机
- Android版本更新完毕自动开启APP应用
- 自定义控件(29)---onTouchEvent与Scroller
- YOLO:You Only Look Once 论文阅读
- SSE入门
- CAFFE 编译成功了
- 比较好的js资源站
- gabor小波滤波器的在纹理提取、图像匹配上的作用
- 继承object对象对python多继承的影响
- iOS 10 开发适配系列 之 权限Crash问题
- Java设计模式之迭代子模式