自定义ViewGroup实现垂直滑屏
2015-04-23 15:49
183 查看
我们都知道ViewPager可以实现水平的滑屏,但是有时候我们需求设计成垂直滑动,该怎么做呢?下面直接上代码:
首先自定义ViewGroup:
2.Activity的布局文件:
activity_main.xml:
activity_main2.xml
activity_main3.xml
activity_main4.xml
注意 guide03,guide04和guide05三张图片 你随便在网上找几张图片就可以了.
源码下载
首先自定义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三张图片 你随便在网上找几张图片就可以了.
源码下载
相关文章推荐
- css实现图片在div中水平和垂直居中(但图片宽高要小于div宽高)
- 自定义ViewGroup实现垂直滚动
- CSS实现水平/垂直自适应浏览器居中【转】
- android TextView 垂直自动滚动字幕实现
- 水平居中和transform: translateY(-50%) 实现元素垂直居中效果
- 纯css实现垂直导航栏
- 实现网页内容水平或垂直滚动的Javascript代码
- 跟随垂直滚动条滚动的DIV实现
- Android中滑屏实现----手把手教你如何实现触摸滑屏以及Scroller类详解
- 纯js代码实现未知宽高的元素在指定元素中垂直水平居中显示
- css 实现垂直居中的 N 种场景及 N 种方法
- How:android开发中实现TextView垂直滚屏效果的方法
- CSS垂直居中的11种实现方式
- 附两个自己认为比较重要的链接地址(移动端的position:fixed,flexbox实现垂直居中布局)
- Android中TextView如何实现水平和垂直滚动
- CSS实现垂直水平居中
- 实现盒子的垂直水平居中
- css实现的让图片垂直居中的方法
- CSS实现垂直居中的5种方法
- 自定义ViewGroup实现仿淘宝的商品详情页