自定义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>


activity_main2.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/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
原创粉丝点击