自定义ViewGroup实现垂直滑屏
来源:互联网 发布:灯光设计软件 编辑:程序博客网 时间:2024/05/21 08:43
我们都知道ViewPager可以实现水平的滑屏,但是有时候我们需求设计成垂直滑动,该怎么做呢?下面直接上代码:
首先自定义ViewGroup:
package com.example.group;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewGroup;import android.widget.Scroller;public class MainGroup extends ViewGroup {float mLastionMotionY = 0 ; //记录上次的触摸位置Scroller scroller; //页面滑动类VelocityTracker velocityTracker; //手势速率跟踪 ,根据触摸位置计算每像素的移动速率int SNAP_VELOCITY = 100; //滑动的最小速率int currentScreen = 0; //第一屏幕private OnPageScrollListener mPageScrollListener;public MainGroup(Context context, AttributeSet attrs) {super(context, attrs);scroller = new Scroller(context);// TODO Auto-generated constructor stub}//onLayout 在自定义控件中 作用将决定 子控件的摆放方式(如:水平,垂直)@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubint totalHeight = 0;int childCount = getChildCount();for (int i = 0; i < childCount; i++) {View childView = getChildAt(i);if(childView.getVisibility() != View.GONE){int childWidth = childView.getMeasuredWidth();int childHeight = childView.getMeasuredHeight();//childView.layout(totalWidth, 0, totalWidth+childWidth, childHeight);childView.layout(0, totalHeight, childWidth, totalHeight+childHeight);totalHeight += childHeight;}}}//onMeasure 作用是用来测量每个子控件的宽高 最后决定自定义控件需要多少空间@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);//获取子View的宽高int width = measureWidth(widthMeasureSpec);int height = measureHeight(heightMeasureSpec);//计算ziView尺寸measureChildren(widthMeasureSpec, heightMeasureSpec);//计算自定义View的尺寸setMeasuredDimension(width, height);}//计算子View的宽度public int measureWidth(int widthMeasureSpec){int result = 0;int measureMode = MeasureSpec.getMode(widthMeasureSpec);int width = MeasureSpec.getSize(widthMeasureSpec);switch (measureMode) {case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY:result = width;break;default:break;}return result;}//计算子View的高度public int measureHeight(int heightMeasureSpec){int result = 0;int measureMode = MeasureSpec.getMode(heightMeasureSpec);int height = MeasureSpec.getSize(heightMeasureSpec);switch (measureMode) {case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY:result = height;break;default:break;}return result;}//onTouchEvent 主要是对 手势操作的处理(如:页面的滑动方向) @Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubfloat y = event.getY();if(velocityTracker == null){velocityTracker = VelocityTracker.obtain();}//添加触摸对象MotionEvent , 用于计算触摸速率velocityTracker.addMovement(event);//捕获 手势(DOWN,UP,MOVE,CANCEL)int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:if(scroller != null){ if(!scroller.isFinished()){ scroller.abortAnimation(); } } mLastionMotionY = y;break;case MotionEvent.ACTION_MOVE:int detalY = (int) (mLastionMotionY-y);//detalY>0 向上滑动 , detalY<0 向下滑动int scrollY = getScrollY();// 边界检查 防止页面滑动超出 显示区域if (detalY < 0 && scrollY + detalY < 0) { //detalX<0 向右滑动,如果不超出左屏幕显示边界 scrollX的绝对值永远是大于detalX滑动的手势距离detalY = 0 - scrollY; //如果进入此条件,其实只有一种情况,那就是 scrollX = 0 的情况} else if (detalY > 0 && scrollY + detalY > (getChildCount()-1)*getHeight()) {// detalX>0 向左滑动, 如果不超出 右屏幕显示边界,scrollX的绝对值永远是 小于或等于ViewGroup的宽度的detalY = (getChildCount()-1)*getHeight() - scrollY;//如果进入此条件,也只有一种情况,那就是 scrollX=ViewGroup的宽度}//在原来离远点x坐标 基础上滑动detalX距离scrollBy(0, detalY); mLastionMotionY = y;break;case MotionEvent.ACTION_UP:velocityTracker.computeCurrentVelocity(1000);int velocityY = (int) velocityTracker.getYVelocity();//velocityY < 0 表示向上滑动的速度为负,velocityY > 0 表示向下滑动的速度为正if(velocityY < -SNAP_VELOCITY){//向上snapToScreen(currentScreen+1);}else if(velocityY > SNAP_VELOCITY){ //向下snapToScreen(currentScreen-1);}else{snapToDestination();}if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } break;default:break;}return true;}@Overridepublic void computeScroll() {// TODO Auto-generated method stubsuper.computeScroll();if(scroller.computeScrollOffset()){scrollTo(scroller.getCurrX(), scroller.getCurrY());postInvalidate();}}private void snapToDestination() {// TODO Auto-generated method stub//当屏幕滑到getWidth()/2 的时候,此时总共有多少屏,即滑到第几屏int whichScreen = ( getScrollY() + getHeight()/2 ) / getHeight();snapToScreen(whichScreen);}//加上动画 缓慢的滑动public void snapToScreen(int whichScreen){currentScreen = whichScreen;if(currentScreen > getChildCount() - 1) currentScreen = getChildCount() - 1 ; if(currentScreen < 0) currentScreen = 0;// 需要滑动的距离 ( 开始 - 剩下 = 需要滑动的距离 ) //getScrollX() 滑出屏幕的第一页 开始到 左屏幕边界的距离int dy = currentScreen*getHeight() - getScrollY();scroller.startScroll(0, getScrollY(), 0, dy, Math.abs(dy) * 1);mPageScrollListener.onPageChanged(currentScreen%3, currentScreen);postInvalidate();}public void setOnPageScrollListener(OnPageScrollListener listener) {mPageScrollListener = listener;}public interface OnPageScrollListener {public void onPageChanged(int position,int real_position);}}
2.Activity的布局文件:
activity_main.xml:
<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" > <com.example.group.MainGroup android:id="@+id/mGroup" android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/activity_main2" /> <include layout="@layout/activity_main3" /> <include layout="@layout/activity_main4" /> </com.example.group.MainGroup></RelativeLayout>
<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" > <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/guide03" /> </RelativeLayout>
activity_main3.xml
<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" > <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/guide04" /></RelativeLayout>
activity_main4.xml
<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" > <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/guide05" /></RelativeLayout>
注意 guide03,guide04和guide05三张图片 你随便在网上找几张图片就可以了.
源码下载
0 0
- 自定义ViewGroup实现垂直滑屏
- 自定义ViewGroup实现垂直滚动
- 自定义ViewGroup实现垂直滚动
- 自定义ViewGroup实现垂直滚动
- 自定义ViewGroup实现垂直滚动
- 自定义ViewGroup实现滑屏等动作
- 自定义垂直方向滑动的ViewGroup
- Android自定义ViewGroup:实现简单的垂直方向线性布局(2)
- Android自定义ViewGroup:实现简单的垂直方向线性布局(2)
- 自定义ViewGroup实现侧滑删除菜单
- 自定义ViewGroup实现左滑效果
- 自定义ViewGroup实现ArcMenu
- 自定义viewgroup实现ArcMenu
- 自定义ViewGroup实现换行
- Android自定义组件系列【3】自定义ViewGroup实现侧滑
- 自定义ViewGroup实现水平滑动
- Android 自定义ViewGroup实现GridLayout
- Android 自定义ViewGroup 实现FlowLayout
- Hibernate复习笔记(二)---annotation的使用
- Things to follow
- 这家伙去年赚了45万美金,可他却不会写一行代码。
- MySQL授权解决不能远程登录的问题
- Linux下编译安装PCRE库
- 自定义ViewGroup实现垂直滑屏
- Linux串口编程_termios
- Scramble String -- leetcode
- 欢迎使用CSDN-markdown编辑器
- 第十六章 内存管理(1)====高质量程序设计指南C/C++编程
- zoj 1648 Grandpa's Estate(判断线段是否相交(不考虑端点相交))
- ADB操作常见问题汇总
- 关于react native运用的简单总结
- mysql数据备份导入导出详解