在好例子网,分享、交流、成长!
您当前所在位置:首页Java 开发实例Android平台开发 → android 滑动滚屏的实现 例子 附完整源码

android 滑动滚屏的实现 例子 附完整源码

Android平台开发

下载此实例
  • 开发语言:Java
  • 实例大小:0.06M
  • 下载次数:17
  • 浏览次数:308
  • 发布时间:2013-07-30
  • 实例类别:Android平台开发
  • 发 布 人:crazycode
  • 文件格式:.rar
  • 所需积分:2
 相关标签: Android

实例介绍

【实例简介】滑动滚屏           
【实例截图】

【核心代码】

package com.qin.scrollerview;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;

//自定义ViewGroup , 包含了三个LinearLayout控件,存放在不同的布局位置,通过scrollBy或者scrollTo方法切换
public class MultiViewGroup extends ViewGroup {

	private Context mContext;
	
	private static String TAG = "MultiViewGroup";
    private int curScreen = 0 ;  //当前屏
	
    private Scroller mScroller = null ;
    
    
	public MultiViewGroup(Context context) {
		super(context);
		mContext = context;
		init();
	}

	public MultiViewGroup(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		init();
	}
   //startScroll 滑屏
	public void startMove(){
		curScreen    ;
		Log.i(TAG, "----startMove---- curScreen "   curScreen);
		
		Log.i(TAG, "----width  "   getWidth());
		//采用Scroller类控制滑动过程
		mScroller.startScroll((curScreen-1) *getWidth(), 0, 
				getWidth(), 0,3000);
		//暴力点直接到目标出
		//scrollTo(curScreen * getWidth(), 0);
		//其实在点击按钮的时候,就回触发View绘制流程,这儿我们在强制绘制下View
		invalidate();
	}
	//停止滑屏
	public void stopMove(){
		
		Log.v(TAG, "----stopMove ----");
		
		if(mScroller != null){
			//如果动画还没结束,我们就按下了结束的按钮,那我们就结束该动画,即马上滑动指定位置
			if(!mScroller.isFinished()){
				
				int scrollCurX= mScroller.getCurrX() ;
              	//判断是否达到下一屏的中间位置,如果达到就抵达下一屏,否则保持在原屏幕
				//int moveX = scrollCurX - mScroller.getStartX()   ;
                // Log.i(TAG, "----mScroller.is not finished ---- shouldNext"   shouldNext);
				//boolean shouldNext = moveX >= getWidth() / 2 ;
				int descScreen = ( scrollCurX    getWidth() / 2) /  getWidth() ;
				
				Log.i(TAG, "----mScroller.is not finished ---- shouldNext"   descScreen);
				
				Log.i(TAG, "----mScroller.is not finished ---- scrollCurX "   scrollCurX);
				mScroller.abortAnimation();

			    //停止了动画,我们马上滑倒目标位置
				scrollTo(descScreen * getWidth() , 0);
				mScroller.forceFinished(true);
				
				curScreen = descScreen ;
			}
	    }
			else
				Log.i(TAG, "----OK mScroller.is  finished ---- ");
	}
	// 只有当前LAYOUT中的某个CHILD导致SCROLL发生滚动,才会致使自己的COMPUTESCROLL被调用
	@Override
	public void computeScroll() {	
		// TODO Auto-generated method stub
		Log.e(TAG, "computeScroll");
		// 如果返回true,表示动画还没有结束
		// 因为前面startScroll,所以只有在startScroll完成时 才会为false
		if (mScroller.computeScrollOffset()) {
			Log.e(TAG, mScroller.getCurrX()   "======"   mScroller.getCurrY());
			// 产生了动画效果 每次滚动一点
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			
			Log.e(TAG, "### getleft is "   getLeft()   " ### getRight is "   getRight());
			
		    //刷新View 否则效果可能有误差
			postInvalidate();
		}
		else
			Log.i(TAG, "have done the scoller -----");
	}
	/////以上可以演示Scroller类的使用
	//// --------------------------------
	/////--------------------------------
	
	private static final int TOUCH_STATE_REST = 0;
	private static final int TOUCH_STATE_SCROLLING = 1;
	private int mTouchState = TOUCH_STATE_REST;
	//-------------------------- 
	//处理触摸事件 ~
	public static int  SNAP_VELOCITY = 600 ;
	private int mTouchSlop = 0 ;
	private float mLastionMotionX = 0 ;
	private float mLastMotionY = 0 ;
	//处理触摸的速率
	private VelocityTracker mVelocityTracker = null ;
	
	// 这个感觉没什么作用 不管true还是false 都是会执行onTouchEvent的 因为子view里面onTouchEvent返回false了
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		// TODO Auto-generated method stub
		Log.e(TAG, "onInterceptTouchEvent-slop:"   mTouchSlop);

		final int action = ev.getAction();
		//表示已经开始滑动了,不需要走该Action_MOVE方法了(第一次时可能调用)。
		if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {
			return true;
		}

		final float x = ev.getX();
		final float y = ev.getY();

		switch (action) {
		case MotionEvent.ACTION_MOVE:
			Log.e(TAG, "onInterceptTouchEvent move");
			final int xDiff = (int) Math.abs(mLastionMotionX - x);
			//超过了最小滑动距离
			if (xDiff > mTouchSlop) {
				mTouchState = TOUCH_STATE_SCROLLING;
			}
			break;

		case MotionEvent.ACTION_DOWN:
			Log.e(TAG, "onInterceptTouchEvent down");
			mLastionMotionX = x;
			mLastMotionY = y;
			Log.e(TAG, mScroller.isFinished()   "");
			mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;

			break;

		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			Log.e(TAG, "onInterceptTouchEvent up or cancel");
			mTouchState = TOUCH_STATE_REST;
			break;
		}
		Log.e(TAG, mTouchState   "===="   TOUCH_STATE_REST);
		return mTouchState != TOUCH_STATE_REST;
	}
	public boolean onTouchEvent(MotionEvent event){
		
		Log.i(TAG, "--- onTouchEvent--> " );

		// TODO Auto-generated method stub
		Log.e(TAG, "onTouchEvent start");
		if (mVelocityTracker == null) {
			
			Log.e(TAG, "onTouchEvent start-------** VelocityTracker.obtain");
			
			mVelocityTracker = VelocityTracker.obtain();
		}
		
		mVelocityTracker.addMovement(event);
		
		super.onTouchEvent(event);
		
		//手指位置地点
		float x = event.getX();
		float y = event.getY();
		
		
		switch(event.getAction()){
		case MotionEvent.ACTION_DOWN:
			//如果屏幕的动画还没结束,你就按下了,我们就结束该动画
			if(mScroller != null){
				if(!mScroller.isFinished()){
					mScroller.abortAnimation();
				}
			}
			
			mLastionMotionX = x ;
			break ;
		case MotionEvent.ACTION_MOVE:
			int detaX = (int)(mLastionMotionX - x );
			scrollBy(detaX, 0);
			
			Log.e(TAG, "--- MotionEvent.ACTION_MOVE--> detaX is "   detaX );
			mLastionMotionX = x ;
			
			break ;
		case MotionEvent.ACTION_UP:
			
			final VelocityTracker velocityTracker = mVelocityTracker  ;
			velocityTracker.computeCurrentVelocity(1000);
			
			int velocityX = (int) velocityTracker.getXVelocity() ;
			
			Log.e(TAG , "---velocityX---"   velocityX);
			
			//滑动速率达到了一个标准(快速向右滑屏,返回上一个屏幕) 马上进行切屏处理
			if (velocityX > SNAP_VELOCITY && curScreen > 0) {
				// Fling enough to move left
				Log.e(TAG, "snap left");
				snapToScreen(curScreen - 1);
			}
			//快速向左滑屏,返回下一个屏幕)
			else if(velocityX < -SNAP_VELOCITY && curScreen < (getChildCount()-1)){
				Log.e(TAG, "snap right");
				snapToScreen(curScreen   1);
			}
			//以上为快速移动的 ,强制切换屏幕
			else{
				//我们是缓慢移动的,因此先判断是保留在本屏幕还是到下一屏幕
				snapToDestination();
			}
			
			if (mVelocityTracker != null) {
				mVelocityTracker.recycle();
				mVelocityTracker = null;
			}
			
			mTouchState = TOUCH_STATE_REST ;
			
		    break;
		case MotionEvent.ACTION_CANCEL:
			mTouchState = TOUCH_STATE_REST ;
			break;
		}
		
		return true ;
	}
	////我们是缓慢移动的
	private void snapToDestination(){
		//当前的偏移位置
		int scrollX = getScrollX() ;
		int scrollY = getScrollY() ;
		
		Log.e(TAG, "### onTouchEvent snapToDestination ### scrollX is "   scrollX);

		//判断是否超过下一屏的中间位置,如果达到就抵达下一屏,否则保持在原屏幕	
		//直接使用这个公式判断是哪一个屏幕 前后或者自己
		//判断是否超过下一屏的中间位置,如果达到就抵达下一屏,否则保持在原屏幕
		// 这样的一个简单公式意思是:假设当前滑屏偏移值即 scrollCurX 加上每个屏幕一半的宽度,除以每个屏幕的宽度就是
		//  我们目标屏所在位置了。 假如每个屏幕宽度为320dip, 我们滑到了500dip处,很显然我们应该到达第二屏	
		int destScreen = (getScrollX()   getWidth() / 2 ) / getWidth() ;
		
		 
	    Log.e(TAG, "### onTouchEvent  ACTION_UP### dx destScreen "   destScreen);
		
		snapToScreen(destScreen);
	}
    private void snapToScreen(int whichScreen){	
	    //简单的移到目标屏幕,可能是当前屏或者下一屏幕
	    //直接跳转过去,不太友好
	    //scrollTo(mLastScreen * getWidth(), 0);
	    //为了友好性,我们在增加一个动画效果
	    //需要再次滑动的距离 屏或者下一屏幕的继续滑动距离

	    curScreen = whichScreen ;
	    
	    if(curScreen > getChildCount() - 1)
	    	curScreen = getChildCount() - 1 ;
	    
	    int dx = curScreen*getWidth() - getScrollX() ;
	    
	    Log.e(TAG, "### onTouchEvent  ACTION_UP### dx is "   dx);
	    
	    mScroller.startScroll(getScrollX(), 0, dx, 0,Math.abs(dx) * 2);
	    
	    //此时需要手动刷新View 否则没效果
	    invalidate();
	    
    }
		
    private void init() {
		
		mScroller = new Scroller(mContext);
		
		// 初始化3个 LinearLayout控件
		LinearLayout oneLL = new LinearLayout(mContext);
		oneLL.setBackgroundColor(Color.RED);
        addView(oneLL);
		
		LinearLayout twoLL = new LinearLayout(mContext);
		twoLL.setBackgroundColor(Color.YELLOW);
		addView(twoLL);
		
		LinearLayout threeLL = new LinearLayout(mContext);
		threeLL.setBackgroundColor(Color.BLUE);
		addView(threeLL);
		
		//初始化一个最小滑动距离
		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
	}

	// measure过程
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		Log.i(TAG, "--- start onMeasure --");

		// 设置该ViewGroup的大小
		int width = MeasureSpec.getSize(widthMeasureSpec);
		int height = MeasureSpec.getSize(heightMeasureSpec);
		setMeasuredDimension(width, height);

		int childCount = getChildCount();
		Log.i(TAG, "--- onMeasure childCount is -->"   childCount);
		for (int i = 0; i < childCount; i  ) {
			View child = getChildAt(i);
			// 设置每个子视图的大小 , 即全屏
			child.measure(getWidth(), MultiScreenActivity.scrrenHeight);
		}
	}

	private int curPage = 0 ;
	
	// layout过程
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		Log.i(TAG, "--- start onLayout --");
		int startLeft = 0; // 每个子视图的起始布局坐标
		int startTop = 10; // 间距设置为10px 相当于 android:marginTop= "10px"
		int childCount = getChildCount();
		Log.i(TAG, "--- onLayout childCount is -->"   childCount );

		for (int i = 0; i < childCount; i  ) {
			View child = getChildAt(i);
			
			//即使可见的,才划到屏幕上
			if(child.getVisibility() != View.GONE)
			    child.layout(startLeft, startTop, 
					   startLeft   getWidth(), 
					   startTop   MultiScreenActivity.scrrenHeight );
			    
			    startLeft = startLeft   getWidth() ; //校准每个子View的起始布局位置
			    //三个子视图的在屏幕中的分布如下 [0 , 320] / [320,640] / [640,960]
		}
	}
}

标签: Android

实例下载地址

android 滑动滚屏的实现 例子 附完整源码

不能下载?内容有错? 点击这里报错 + 投诉 + 提问

好例子网口号:伸出你的我的手 — 分享

网友评论

发表评论

(您的评论需要经过审核才能显示)

查看所有0条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警