`
goblin_god
  • 浏览: 54634 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

滑动效果

阅读更多

 

package com.test.canvas;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.SpinnerAdapter;

public class Switcher extends ViewGroup {

	private static final int SCROLL = 0;
	private static final int JUSTIFY = 1;
	private static final int DISMISS_CONTROLS = 2;

//	private static final int ANIMATION_DURATION = 750;
//	private static final int IDLE_TIMEOUT = 3 * 1000;
	
	private int mOrientation;
	//宽度或高度,具体根据Orientation来决定
	private int mSize;
	//private Drawable mDecreaseButtonDrawable;
	//private Drawable mIncreaseButtonDrawable;
	//private ImageButton mDecreaseButton;
	//private ImageButton mIncreaseButton;
	//private PopupWindow mDecreasePopup;
	//private PopupWindow mIncreasePopup;
	private int mIndex;
	private int mPosition;
	private Scroller mScroller;
	private Map<View, Integer> mViews;
	private SpinnerAdapter mAdapter;
	private int mPackedViews;
	private GestureDetector mGestureDetector;
	private Rect mGlobal;
	private int mAnimationDuration;
	
	public Switcher(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		int[] linerarLayoutAttrs = {
			android.R.attr.orientation
		};
		TypedArray a = context.obtainStyledAttributes(attrs, linerarLayoutAttrs);
		mOrientation = a.getInteger(0, LinearLayout.HORIZONTAL);
		a.recycle();
		
//		a = context.obtainStyledAttributes(attrs, R.styleable.Switcher);
//		mDecreaseButtonDrawable = a.getDrawable(R.styleable.Switcher_decreaseButton);
//		mIncreaseButtonDrawable = a.getDrawable(R.styleable.Switcher_increaseButton);
//		mAnimationDuration = a.getInteger(R.styleable.Switcher_animationDuration, ANIMATION_DURATION);
//		mIdleTimeout = a.getInteger(R.styleable.Switcher_idleTimeout, IDLE_TIMEOUT);
//		a.recycle();

//		if(mDecreaseButtonDrawable == null) {
//			throw new IllegalArgumentException(a.getPositionDescription() + ": decreaseButton attrubute not specified.");
//		}
//		if(mIncreaseButtonDrawable == null) {
//			throw new IllegalArgumentException(a.getPositionDescription() + ": increaseButton attrubute not specified.");
//		}

//		mDecreaseButton = new ImageButton(context);
//		mDecreaseButton.setEnabled(false);
//		mDecreaseButton.setBackgroundDrawable(mDecreaseButtonDrawable);
//		mIncreaseButton = new ImageButton(context);
//		mIncreaseButton.setEnabled(false);
//		mIncreaseButton.setBackgroundDrawable(mIncreaseButtonDrawable);
//
//		mDecreaseButton.setOnClickListener(new OnClickListener() {
//			public void onClick(View v) {
//				setPreviousView();
//			}
//		});
//		mIncreaseButton.setOnClickListener(new OnClickListener() {
//			public void onClick(View v) {
//				setNextView();
//			}
//		});

		mScroller = new Scroller(context);
		mIndex = -1;
		mPosition = -1;
		mPackedViews = -1;
		mViews = new HashMap<View, Integer>();

		mGestureDetector = new GestureDetector(gestureListener);
		mGestureDetector.setIsLongpressEnabled(false);
		setFocusable(true);
		setFocusableInTouchMode(true);
//		mDecreasePopup = new PopupWindow(mDecreaseButton, mDecreaseButtonDrawable.getIntrinsicWidth(), mDecreaseButtonDrawable.getIntrinsicHeight());
//		mIncreasePopup = new PopupWindow(mIncreaseButton, mIncreaseButtonDrawable.getIntrinsicWidth(), mIncreaseButtonDrawable.getIntrinsicHeight());
//		mDecreasePopup.setAnimationStyle(android.R.style.Animation_Toast);
//		mIncreasePopup.setAnimationStyle(android.R.style.Animation_Toast);
		mGlobal = new Rect();
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mSize = mOrientation == LinearLayout.HORIZONTAL? getMeasuredWidth() : getMeasuredHeight();
	}

	private int getPackedViews(int offset) {
		int size = mSize;
		int start = offset / size;
		int numViews = offset % size != 0? 1 : 0;
		//都是位操作,从左往右依次执行,如果offset能被size整除则直接得出结果,如果不能整除,则结果再加1.
		return start << 1 | numViews;
	}
	
	Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			if (msg.what == DISMISS_CONTROLS) {
//				mDecreasePopup.dismiss();
//				mIncreasePopup.dismiss();
				return;
			}
			
			Log.v("", "handleMessage-what:"+msg.what);
			
			mScroller.computeScrollOffset();
			int currX = mScroller.getCurrX();
			int delta = mPosition - currX;
			mPosition = currX;
			int packed = getPackedViews(mPosition);
			manageViews(packed);
			scroll(delta);
			if (!mScroller.isFinished()) {
				Log.v("", "mScroller.isFinished()=false");
				handler.sendEmptyMessage(msg.what);
			} else {
				if (msg.what == SCROLL) {
					justify();
				} else {
					mIndex = mPosition / mSize;
					setupButtons();
				}
			}
		}
	};
//	private long mIdleTimeout;

	//最后的矫正
	private void justify() {
		int offset = mPosition % mSize;
		if (offset != 0) {
			int endPosition = mPosition - offset;
			//如果移动超过中线则...
			if (offset > mSize / 2) {
				endPosition += mSize;
			}
			mScroller.startScroll(mPosition, 0, endPosition - mPosition, 0);
			handler.sendEmptyMessage(JUSTIFY);
		} else {
			mIndex = mPosition / mSize;
			setupButtons();
		}
	}

	private void scroll(int offset) {
		if (mOrientation == LinearLayout.HORIZONTAL) {
			for (View view : mViews.keySet()) {
				view.offsetLeftAndRight(offset);
			}
		} else {
			for (View view : mViews.keySet()) {
				view.offsetTopAndBottom(offset);
			}
		}
		invalidate();
	}

	private void setupButtons() {
//		if (mAdapter != null) {
//			boolean enabled = mIndex > 0;
//			mDecreaseButton.setEnabled(enabled);
//			enabled = mIndex + 1 < mAdapter.getCount();
//			mIncreaseButton.setEnabled(enabled);
//		}
	}

	public void setSelection(int index, boolean animate) {
		if (index == mIndex) {
			return;
		}
		int endPosition = index * mSize;
		int diff = Math.abs(index - mIndex);
		int sign = index > mIndex? 1 : -1;
		mIndex = index;
		if (diff > 1) {
			mPosition = endPosition - sign * mSize;
		}
		if (animate) {
			mScroller.startScroll(mPosition, 0, endPosition - mPosition, 0, mAnimationDuration);
			handler.removeMessages(JUSTIFY);
			handler.removeMessages(SCROLL);
			handler.sendEmptyMessage(JUSTIFY);
		} else {
			mPosition = endPosition;
			manageViews(index << 1);
			setupButtons();
			invalidate();
		}
	}
	
	private void manageViews(int packedViews) {
		if (packedViews == mPackedViews) {
			return;
		}
		Log.v("", "manageViews-packedViews:"+packedViews);

		mPackedViews = packedViews;
		int startIdx = packedViews >> 1;
		int endIdx = startIdx + (packedViews & 1);//如果packedViews是奇数endIdx=startIdx,如果是偶数则endIdx=startIdx+1.
		int viewIdx = startIdx;
		while (viewIdx <= endIdx) {
			if (!mViews.containsValue(viewIdx)) {
				if (viewIdx >= 0 && viewIdx < mAdapter.getCount()) {
					View view = mAdapter.getView(viewIdx, null, this);
					mViews.put(view, viewIdx);
					addView(view);
				}
			}
			viewIdx++;
		}

		// remove not visible views
		Iterator<View> iterator = mViews.keySet().iterator();
		while (iterator.hasNext()) {
			View view = iterator.next();
			int idx = mViews.get(view);
			if (idx < startIdx || idx > endIdx) {
				iterator.remove();
				removeView(view);
			}
		}
	}

//	public int getSelection() {
//		return mIndex;
//	}
//	
//	public void setPreviousView() {
//		if (mAdapter != null && mIndex > 0) {
//			setSelection(mIndex-1, true);
//			setupDismiss();
//		}
//	}
//
//	public void setNextView() {
//		if (mAdapter != null && mIndex + 1 < mAdapter.getCount()) {
//			setSelection(mIndex+1, true);
//			setupDismiss();
//		}
//	}
	
	public void setAdapter(SpinnerAdapter adapter) {
		mAdapter = adapter;
		if (mAdapter != null) {
			setSelection(0, false);
			setupButtons();
		}
	}
	
	private void setupDismiss() {
//		handler.removeMessages(DISMISS_CONTROLS);
//		handler.sendEmptyMessageDelayed(DISMISS_CONTROLS, mIdleTimeout);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		boolean rc = mGestureDetector.onTouchEvent(event);
		//有数据时应该是没有机会执行里面的代码
		if (!rc && event.getAction() == MotionEvent.ACTION_UP) {
			justify();
		}
		return true;
	}

	SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
		@Override
		public boolean onDown(MotionEvent e) {
			requestFocus();
			popup();
			return true;
		}
		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
			if (mAdapter != null) {
				int distance = (int) (mOrientation == LinearLayout.HORIZONTAL? distanceX : distanceY);
				int pos = mPosition + distance;
				if (pos >= 0 && pos < (mAdapter.getCount() - 1) * mSize) {
					mPosition = pos;
					int packed = getPackedViews(mPosition);
					manageViews(packed);
					scroll(-distance);
					return true;
				}
			}
			return false;
		}
		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
			if (mAdapter != null) {
				
				Log.v("", "onFling");
				float velocity = mOrientation == LinearLayout.HORIZONTAL? velocityX : velocityY;
				mScroller.fling(mPosition, 0, (int) -velocity, 0,
						0, (mAdapter.getCount() - 1) * mSize,
						0, 0);
				handler.removeMessages(JUSTIFY);
				handler.removeMessages(SCROLL);
				handler.sendEmptyMessage(SCROLL);
				return true;
			}
			return false;
		}
	};

	@Override
	protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
		super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
		if (gainFocus) {
			popup();
		} else {
			handler.removeMessages(DISMISS_CONTROLS);
//			mDecreasePopup.dismiss();
//			mIncreasePopup.dismiss();
		}
	}
	
	private void popup() {
//		if (mDecreasePopup.isShowing() && mIncreasePopup.isShowing()) {
//			return;
//		}
		getGlobalVisibleRect(mGlobal);
//		if (mOrientation == LinearLayout.HORIZONTAL) {
//			mDecreasePopup.showAtLocation(this,
//					Gravity.NO_GRAVITY,
//					mGlobal.left, 
//					mGlobal.centerY() - mDecreasePopup.getHeight()/2);
//			mIncreasePopup.showAtLocation(this,
//					Gravity.NO_GRAVITY,
//					mGlobal.right - mIncreasePopup.getWidth(), 
//					mGlobal.centerY() - mIncreasePopup.getHeight()/2);
//		} else {
//			// TODO: re-position when Switcher is at the very top/bottom of screen
//			mDecreasePopup.showAtLocation(this,
//					Gravity.NO_GRAVITY,
//					mGlobal.centerX() - mDecreasePopup.getWidth()/2,
//					mGlobal.top-mDecreasePopup.getHeight());
//			mIncreasePopup.showAtLocation(this,
//					Gravity.NO_GRAVITY,
//					mGlobal.centerX() - mIncreasePopup.getWidth()/2,
//					mGlobal.bottom);
//		}
		setupDismiss();
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		for (View view : mViews.keySet()) {
			if (view.getWidth() == 0) {
				// new View: not layout()ed
				int idx = mViews.get(view);
				if (mOrientation == LinearLayout.HORIZONTAL) {
					int left = mSize * idx - mPosition;
					view.layout(left, 0, left+r-l, b-t);
				} else {
					int top = mSize * idx - mPosition;
					view.layout(0, top, r-l, top+b-t);
				}
			}
		}
	}
			
	@Override
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
//		mDecreasePopup.dismiss();
//		mIncreasePopup.dismiss();
	}

	public void setInterpolator(Interpolator interpolator) {
		mScroller = new Scroller(getContext(), interpolator);
	}
}
 

 

分享到:
评论

相关推荐

    微信小程序实现卡片层叠滑动效果

    层叠滑动效果是一种常见的UI交互方式,通过滑动可以查看多层卡片信息。在微信小程序中实现卡片层叠滑动效果,可以帮助开发者创建更丰富和直观的用户交互体验。实现该效果需要涉及到微信小程序的前端技术,如wxml、...

    仿emui滑动效果

    在Android应用开发中,滑动效果是用户界面中常见的交互元素,可以提升用户体验。"仿emui滑动效果"指的是模仿华为EMUI(Emotion UI)3.0系统的滑动过渡动画,它使得屏幕间的切换更为流畅自然。EMUI是华为自研的基于...

    LabVIEW滑动效果UI设计.rar

    在这个"LabVIEW滑动效果UI设计"的压缩包中,我们可能找到了关于如何在LabVIEW中实现动态、交互式的用户界面(UI)设计的资源。滑动效果通常指的是在UI中使用滑块或滚动条等控件,让用户能够通过平滑地移动来调节参数...

    仿京东首页沉浸式以及滑动效果

    在IT行业中,尤其是在移动应用开发领域,"仿京东首页沉浸式以及滑动效果"是一个常见的设计实践,旨在提供用户更加沉浸式的浏览体验。这个标题暗示我们要讨论的是如何在Android或iOS应用中实现类似京东首页那样的界面...

    QT 图片三维立体滑动效果

    QT图片三维立体滑动效果是基于Qt框架实现的一种动态用户界面功能,它为展示图片提供了类似于手机相册的滑动浏览体验。这个功能利用了Qt的图形视图框架(Graphics View Framework)和QGraphicsView类,结合了投影和三...

    jqurey手机版触屏滑动效果

    针对触屏设备,jQuery提供了多种方法来实现流畅的滑动效果,以增强用户体验。本教程将深入探讨如何利用jQuery实现适用于各种浏览器的手机版触屏滑动效果。 首先,为了在触屏设备上实现滑动效果,我们需要引入jQuery...

    手机版网站,滑动效果案例.

    滑动效果是许多现代手机网站不可或缺的元素,它为用户提供了流畅、直观的交互体验。在这个案例中,我们将深入探讨如何在触屏手机网站上实现这样的滑动效果。 首先,我们要理解滑动效果的基本原理。在触屏设备上,...

    android滑动效果集合+源码

    在Android开发中,滑动效果是用户界面设计中不可或缺的一部分,为用户提供流畅、直观的交互体验。本资源包“android滑动效果集合+源码”集合了多种Android平台上的滑动动画与交互效果,旨在帮助开发者提升应用的用户...

    java Swing panel button左右滑动效果

    java Swing panel button左右滑动效果

    RecyclerView+CardView实现横向卡片式滑动效果

    RecyclerView+CardView实现横向卡片式滑动效果 本文主要介绍了使用RecyclerView和CardView实现横向卡片式滑动效果的方法,旨在提高Android应用程序的用户体验。下面是相关知识点的详细解释: 1. RecyclerView简介 ...

    类似桌面的弹性滑动效果

    在安卓开发中,实现“类似桌面的弹性滑动效果”是一项常见的需求,它能为用户带来更加生动和直观的操作体验。这种效果通常应用于应用主界面、列表视图或者图片浏览等场景,使得用户可以通过手指的右向左滑动来切换...

    Unity3D图片滑动效果

    ### Unity3D图片滑动效果实现详解 #### 一、概述 在Unity3D中实现图片滑动效果是一项常见的需求,特别是在开发具有交互性的游戏或应用程序时。通过使用C#编程语言结合Unity引擎提供的功能,我们可以轻松地为游戏...

    listview的item滑动效果

    本篇文章将深入探讨如何在ListView的Item上实现滑动效果,以此提升用户体验。 首先,我们需要了解ListView的工作原理。ListView采用滚动复用机制,即只有当前屏幕可见的Item会被实例化,当Item滑出屏幕时,会被回收...

    导航水波纹点击效果外加滑动效果

    "导航水波纹点击效果外加滑动效果"是一种独特的UI设计技术,它结合了视觉吸引力与操作反馈,为用户提供了一种新颖的互动方式。 水波纹效果源于谷歌Material Design设计语言,它的核心思想是模拟现实世界中的物理...

    仿淘宝购物车滑动效果

    在IT行业中,创建类似淘宝购物车的滑动效果是一项常见的前端开发任务,它涉及到用户体验设计和交互技术。这种效果能够使用户在浏览商品时获得流畅的体验,提高网站的吸引力和用户满意度。以下是对这个主题的详细解释...

    e语言-易语言按钮滑动效果

    标题中的“e语言-易语言按钮滑动效果”表明我们要讨论的是如何在易语言中实现一个具有滑动效果的按钮。 在易语言中,通常我们会通过调用API函数来实现一些复杂或特定的功能,如本例中的按钮滑动效果。API...

    JS滑动效果

    滑动效果是网页动态设计中的常见元素,能够为用户界面增添流畅的视觉体验。本文将深入探讨JS如何实现滑动效果,并通过greensock-v12-js这个库来具体阐述。 首先,我们了解滑动效果的基本原理。滑动通常涉及到元素的...

    滑动效果 滑动效果 js 滑动效果

    滑动效果在网页设计和开发中是至关重要的,它能够为用户提供流畅、动态的交互体验。滑动效果通常指的是页面元素(如图片、文本或整个页面)在用户操作下沿着特定方向平滑移动的视觉表现。这种效果广泛应用于轮播图、...

    高仿淘宝首页菜单滑动效果

    高仿淘宝首页菜单滑动效果,不分页。 重要逻辑:通过菜单的偏移量计算PageControl的偏移量 pageControl的偏移量为pageControl的总宽度减去滑块的总宽度, 同理scrollView的偏移量为scrollView的内容宽度减去...

Global site tag (gtag.js) - Google Analytics