您的位置:首页 > 其它

自定义ViewGroup实现垂直滑屏

2015-04-23 15:49 183 查看
我们都知道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 在自定义控件中 作用将决定 子控件的摆放方式(如:水平,垂直)
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub

int 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 作用是用来测量每个子控件的宽高  最后决定自定义控件需要多少空间
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.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 主要是对 手势操作的处理(如:页面的滑动方向)
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
float 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;
}

@Override
public void computeScroll() {
// TODO Auto-generated method stub
super.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三张图片 你随便在网上找几张图片就可以了.

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: