旋转特效的菜单选择

1、java文件:

package us.eiyou.financial_management_service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;

//RotateCard(自定义的旋转view)
//item被点击时有放大的动画效果
//快速滑动后手指放开会有余旋
public class RotateCard extends FrameLayout {

private ArrayList<RotateCardViewHolder> viewHolderList;
private ArrayList<View> viewList;
private int ovalA, ovalB;// 椭圆轨迹的长半轴,短半轴
private int parentWidth, parentHeight;// RotateCard的宽高
private int viewWidth, viewHeight;// viewSet中的View的宽高
LayoutParams viewpParams;// view的LayoutParams
private float angleOffset;// 手指每滑动一像素需要绕椭圆中心旋转的度数

private RotateCardOnTouchListener mTouchListener;// 供RotateCard和子View同时使用,处理滑动事件

// 增加绘制前的监听以获得RotateCard的宽高
private ViewTreeObserver.OnPreDrawListener onPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
parentWidth = RotateCard.this.getMeasuredWidth();
parentHeight = RotateCard.this.getMeasuredHeight();
angleOffset = (float) ((180.0 / parentWidth) * 1.5);

// Log.i(INFO_TAG, "parentWidth:" + parentWidth);
// Log.i(INFO_TAG, "parentHeight:" + parentHeight);
// Log.i(INFO_TAG, "angleOffset:" + angleOffset);

if (viewList != null && viewList.size() > 0) {
afterGetParamsAndViews();
}

// 除去监听
RotateCard.this.getViewTreeObserver().removeOnPreDrawListener(
onPreDrawListener);
return true;
}
};

public RotateCard(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}

public RotateCard(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}

public RotateCard(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}

private void init() {
// 增加RotateCard绘制之前的监听
RotateCard.this.getViewTreeObserver().addOnPreDrawListener(
onPreDrawListener);

// 增加RotateCard的滑动监听
mTouchListener = new RotateCardOnTouchListener();
this.setOnTouchListener(mTouchListener);
}

/**
* 必须保证传入的View集合的每个View的大小一致,否则显示可能不准确
*
* @param viewSet
* View集合
*/
public void commitViews(ArrayList<View> viewList, int viewWidth,
int viewHeight) {
this.removeAllViews();
this.viewList = viewList;
this.viewWidth = viewWidth;
this.viewHeight = viewHeight;
viewpParams = new LayoutParams(viewWidth, viewHeight);
// Log.i(INFO_TAG, "viewWidth:" + viewWidth);
// Log.i(INFO_TAG, "viewHeight:" + viewHeight);

if (parentWidth != 0 && parentHeight != 0) {
afterGetParamsAndViews();
}
}

/**
* 必须保证传入的View集合的每个View的大小一致,否则显示可能不准确
* 应该没有谁的view不是圆形或正方形吧?输入直径或边长就好了
*
* @param viewSet
* View集合
*/
public void commitViews(ArrayList<View> viewList, int viewWidthHeight) {
this.removeAllViews();
this.viewList = viewList;
this.viewWidth = viewWidthHeight;
this.viewHeight = viewWidthHeight;
viewpParams = new LayoutParams(viewWidth, viewHeight);
// Log.i(INFO_TAG, "viewWidth:" + viewWidth);
// Log.i(INFO_TAG, "viewHeight:" + viewHeight);

if (parentWidth != 0 && parentHeight != 0) {
afterGetParamsAndViews();
}
}

/**
* 在获得RotateCard后并且调用过commitViews函数后,此函数被调用
*/
private void afterGetParamsAndViews() {

ovalA = (parentWidth - viewWidth) / 2;
ovalB = (int) ((parentHeight - viewHeight * 1.5) / 2);

int viewNum = viewList.size();
float anglePerView = (float) (360.0 / viewNum);

// Log.i(INFO_TAG, "ovalA:" + ovalA);
// Log.i(INFO_TAG, "ovalB:" + ovalB);
// Log.i(INFO_TAG, "viewNum:" + viewNum);
// Log.i(INFO_TAG, "anglePerView:" + anglePerView);

if (viewHolderList == null) {
viewHolderList = new ArrayList<RotateCardViewHolder>();
} else {
viewHolderList.clear();
}

float tmpAngle = 270.0f;// 第一个view在270度的位置,即最前的位置
for (int i = 0; i < viewNum; ++i) {
int index = i + 1;
View view = viewList.get(i);
// 添加子view的滑动事件监听
view.setOnTouchListener(mTouchListener);
// 添加子view的点击事件监听
view.setOnClickListener(new ItemOnClickListener(index));
// 为子view创建一个RotateCardViewHolder
RotateCardViewHolder holder = new RotateCardViewHolder(view,
tmpAngle, index);
// 将holder捆绑在子view上,方面从子view直接获取holder
view.setTag(holder);
viewHolderList.add(holder);

// 增加anglePerView的角度,用于确定下一个view的位置
tmpAngle += anglePerView;
}
// 把子view添加到RotateCard中
loadViewBySequence();
}

/**
* 把所有view旋转angleDiff的角度
*
* @param angleDiff
* 旋转的角度
*/
private void rotateViewsByAngle(float angleDiff) {
// 若有动画在进行,则不进行旋转
if (set != null && set.isRunning()) {
return;
}
// 旋转每一个view
for (RotateCardViewHolder holder : viewHolderList) {
holder.setAngle(holder.getAngle() + angleDiff);
}
// 重新载入view以确保他们正确的遮挡关系
loadViewBySequence();
}

/**
* 通过对vew排序后重新把view添加到RotateCard中来决定他们的遮挡关系 ,越靠前的view越慢添加
*/
private void loadViewBySequence() {
Collections.sort(viewHolderList, new RotateCardViewHolderComparator());
this.removeAllViews();
for (RotateCardViewHolder holder : viewHolderList) {
this.addView(holder.getView(), viewpParams);
}
}

/**
* 封装对view的一些操作
*/
public class RotateCardViewHolder {
private View mView;
private float mAngle;
private int index;

public RotateCardViewHolder(View view, float angle, int index) {
this.mView = view;
this.mAngle = angle;
this.index = index;
setAngle(angle);
}

/**
* 设置位置和大小
*/
public void resetPositionAndScale() {
// 设置大小
float angleDiff = getAngleDiffWith90();
float scale = (float) ((1.0 * angleDiff / 180) * 0.75 + 0.25);
mView.setScaleX(scale);
mView.setScaleY(scale);

// 设置位置
float x = (float) (ovalA * Math.cos(mAngle / 180.0 * Math.PI)
+ parentWidth / 2 - viewWidth / 2);
float y = (float) (parentHeight / 2 - ovalB
* Math.sin(mAngle / 180.0 * Math.PI) - viewHeight / 2);
mView.setX(x);
mView.setY(y);
}

/**
* 设置view的角度,同时改变他的显示的大小和位置
*
* @param angle
* view的角度
*/
public void setAngle(float angle) {
// 保证mAngle在0~360之间
mAngle = angle;
while (mAngle < 0 || mAngle > 360) {
if (mAngle < 0) {
mAngle = (mAngle + 360) % 360;
} else {
mAngle = mAngle % 360;
}
}
resetPositionAndScale();
}

/**
* 获取view的角度
*
* @return view的角度
*/
public float getAngle() {
return mAngle;
}

/**
* 获取view一开始的序号
*
* @return view的序号
*/
public int getIndex() {
return index;
}

/**
* 获取view的实例
*
* @return view的实例
*/
public View getView() {
return mView;
}

/**
* 获取该view当前位置跟90度位置相差的度数
*
* @return 跟90度相差的度数
*/
public float getAngleDiffWith90() {
float tmpAngle = mAngle > 270 ? mAngle - 360 : mAngle;
float angleDiff = Math.abs(tmpAngle - 90);
return angleDiff;
}

/**
* 获取该view当前位置跟270度位置相差的度数
*
* @return 跟270度相差的度数
*/
public float getAngleDiffWith270() {
float tmpAngle = mAngle < 90 ? mAngle + 360 : mAngle;
float angleDiff = Math.abs(tmpAngle - 270);
return angleDiff;
}

}

/**
* 比较器,用来把view按照度数越接近270度越靠后的顺序排序
*
*/
public class RotateCardViewHolderComparator implements
Comparator<RotateCardViewHolder> {

@Override
public int compare(RotateCardViewHolder a, RotateCardViewHolder b) {
// TODO Auto-generated method stub
return a.getAngleDiffWith270() > b.getAngleDiffWith270() ? -1 : 1;

}
}

private float lastX, nowX;// 上次手指的x坐标位置和当前手指的x坐标位置
private VelocityTracker vTracker;// 监控手指滑动的使用率
private AnimatorSet set;// 动画集
private boolean justCancelAnimation = false;// 是否刚刚通过点击屏幕使正在进行的动画取消,用于取消动画的同事发生的点击事件

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: {
// 若动画正在进行,则取消动画
if (set != null && set.isRunning()) {
set.cancel();
set = null;
justCancelAnimation = true;
}
// 获取VelocityTracker的一个实例
vTracker = VelocityTracker.obtain();
// 记录lastX
lastX = event.getX();
}
break;
case MotionEvent.ACTION_MOVE: {
justCancelAnimation = false;
// 把动作送到vTracker
vTracker.addMovement(event);
// 记录nowX
nowX = event.getX();
}
break;
case MotionEvent.ACTION_UP: {
if (justCancelAnimation) {
justCancelAnimation = false;
return true;// 用来取消点击事件
}
// 设置计算单元,为1秒
vTracker.computeCurrentVelocity(1000);
// 获取在x轴方向1秒内划过的像素数
float xSpeed = vTracker.getXVelocity();
// 活动过快,则执行动画,让RotateCard再旋转一会才停下
if (Math.abs(xSpeed) > 800.0f) {
// 还要旋转的角度
float angleDiff = xSpeed / 10;
// 还要旋转的时间
int duration = (int) (Math.abs(angleDiff) / 180 * 1000);

// 设置动画集
set = new AnimatorSet();
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f)
.setDuration(duration);
animation.addUpdateListener(new AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
// TODO Auto-generated method stub
loadViewBySequence();
}

});
set.play(animation);
for (RotateCardViewHolder _holder : viewHolderList) {
ObjectAnimator oa = ObjectAnimator.ofFloat(_holder,
"angle", _holder.getAngle(),
_holder.getAngle() + angleDiff).setDuration(
duration);
oa.setInterpolator(new DecelerateInterpolator());
set.play(oa).with(animation);
}
// 开始动画集合
set.start();
}
}
break;
}
return super.dispatchTouchEvent(event);
}

private class RotateCardOnTouchListener implements OnTouchListener {

@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: {

}
break;
case MotionEvent.ACTION_MOVE: {
// 此次手指滑动需要旋转的度数
float angleDiff = (nowX - lastX) * angleOffset;
// 旋转angleDiff的角度
rotateViewsByAngle(angleDiff);
// 记录lastX
lastX = nowX;
}
break;
case MotionEvent.ACTION_UP: {

}
break;
}

if (v instanceof RotateCard) {
// 若是手指的位置是RotateCard,返回true让事件继续传递给RotateCard
return true;
} else {
// 若是手指的位置是子view,返回false让子view的点击事件可以响应
return false;
}
}
}

public class ItemOnClickListener implements OnClickListener {

private int index;

public ItemOnClickListener(int index) {
this.index = index;
}

/**
* * 把被点击的view旋转的最前面
*/
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
final View tView = v;
final RotateCardViewHolder holder = (RotateCardViewHolder) v
.getTag();
float angle = holder.getAngle();
// 需要旋转的度数
float angleDiff = angle >= 0.0f && angle <= 90.0f ? -90.0f - angle
: 270.0f - angle;
// 是否子执行view的点击事件(若被点击view在很靠前,则旋转后执行它的点击事件)
final boolean performClick = Math.abs(angleDiff) < 45.0f;
int duration = (int) (Math.abs(angleDiff) / 180 * 1000);

// 初始化动画集
set = new AnimatorSet();
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f)
.setDuration(duration);
animation.addUpdateListener(new AnimatorUpdateListener() {

@Override
public void onAnimationUpdate(ValueAnimator animation) {
// TODO Auto-generated method stub
loadViewBySequence();
}

});
set.play(animation);
if (performClick) {
ObjectAnimator aa = ObjectAnimator.ofFloat(tView, "alpha",
1.0f, 0.5f, 1.0f).setDuration(800);
ObjectAnimator saX = ObjectAnimator.ofFloat(tView, "scaleX",
1.0f, 1.5f, 1.0f).setDuration(800);
ObjectAnimator saY = ObjectAnimator.ofFloat(tView, "scaleY",
1.0f, 1.5f, 1.0f).setDuration(800);
set.play(aa).with(animation);
set.play(saX).with(animation);
set.play(saY).with(animation);
}
for (RotateCardViewHolder _holder : viewHolderList) {
ObjectAnimator oa = ObjectAnimator.ofFloat(_holder, "angle",
_holder.getAngle(), _holder.getAngle() + angleDiff)
.setDuration(duration);
oa.setInterpolator(new DecelerateInterpolator());
set.play(oa).with(animation);
}
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
if (mOnItemClickListener != null && performClick) {
// 执行外部设置的点击事件
mOnItemClickListener.onItemClickListener(tView, index);
}
}

@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
tView.setAlpha(1.0f);
holder.resetPositionAndScale();
}
});
set.start();
}
}

/**
* 子view点击事件监听器OnItemClickListener
*
* RotateCard内部需要自行处理子vew的点击事件,OnItemClickListener监听器供外部代码使用
*/
public interface OnItemClickListener {
public void onItemClickListener(View view, int index);
}

private OnItemClickListener mOnItemClickListener;

/**
* 添加子view点击事件监听
*
* @param onItemClickListener
*/
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.mOnItemClickListener = onItemClickListener;
}
}

2、布局引用:

<us.eiyou.financial_management_service.RotateCard
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" />

3、Activity调用:

/**
* 旋转view
*/
RotateCard card;
ArrayList<View> views;

/**
* 旋转view
*/
card = (RotateCard) findViewById(R.id.card);
views = new ArrayList<View>();

img = new ImageView(getApplicationContext());
img.setImageResource(R.drawable.huilv);
views.add(img);

img = new ImageView(getApplicationContext());
img.setImageResource(R.drawable.cunkuan);
views.add(img);

img = new ImageView(getApplicationContext());
img.setImageResource(R.drawable.fangdai);
views.add(img);

时间: 2024-08-06 15:38:09

旋转特效的菜单选择的相关文章

jQuery可拖拽3D万花筒旋转特效

jQuery可拖拽3D万花筒旋转特效 这是一个使用了CSS3立体效果的强大特效,本特效使用jQuery跟CSS3 transform来实现在用户鼠标按下拖动时,环形图片墙可以跟随鼠标进行3D旋转动画. 效果体验:http://hovertree.com/texiao/jquery/92/ 进去后可以上下左右的拖动图片. 本示例中使用到了CSS3的transform-style 属性,该规定如何在 3D 空间中呈现被嵌套的元素. 默认值: flat继承性: no版本: CSS3JavaScript

android listview级联三菜单选择地区,本地数据库sqlite级联地区,item选中不变色

前言:因为找了N多网上的资源都没有好的解决方案,别人都是只给思路没给具体源码,真TMD纠结,干嘛求别人,自己动手才是真,最痛恨那些所谓大牛的作风,给了点点代码就让别人去想,你让我们这种小白情何于堪!!!!!!此例是基于listview来实现本地sqlite实现的! 二话不说,程序猿求的是有图有真相有源码!大家下载后有什么问题可以找到本人:QQ508181017 核心代码如下 1.数据库操作类 package com.icq.demo.db; import java.util.ArrayList;

示例-下拉菜单-选择颜色

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="

2.CCGridAction(3D效果),3D反转特效,凸透镜特效,液体特效,3D翻页特效,水波纹特效,3D晃动的特效,扭曲旋转特效,波动特效,3D波动特效

 1 类图组织 2 实例 CCSprite * spr = CCSprite::create("HelloWorld.png"); spr->setPosition(ccp(winSize.width/2,winSize.height/2)); addChild(spr); //GridAction //CCFlipX3D * action = CCFlipX3D::create(2); //CCFlipY3D * action = CCFlipY3D::create(2);

c++课程设计之菜单选择\\

a) 从键盘输入n个数,选择升序还是降序输出 b)创新了日历 c) 添加了射箭游戏 d)还加入了好玩的24点游戏     学生签名:  年  月   日   课程设计(论文)评阅意见 等 级 项    目 课程设计态度评价 出勤情况评价 设计中创新性评价 论文书写规范化评价 综合评定等级 优秀 好 好 6补充 好   良好 好 好 4补充 好   中等 好 好 2补充 好   及格 好 好 无补充 好   不及格 不好 不好 无补充 不好   评阅人  王更生  职称  教 授 2017年  6

css3-rotate实现超炫环形旋转特效

css3-rotate实现超炫环形旋转特效,css3特效,环形旋转,圆形旋转,css3-rotate实现超炫环形旋转特效是一款采用css3 rotate实现的蓝色环形旋转特效代码. http://www.huiyi8.com/css3/

基于animation.css实现动画旋转特效

分享一款基于animation.css实现动画旋转特效.这是一款基于CSS3实现的酷炫的动画旋转特效代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="wrap"> <div class="mod_bg"> <div class="bg1"></div> <div class="bg2"></div> <

基于css3的3D立方体旋转特效

今天给大家分享一款基于css3的3D立方体旋转特效.这款特效适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗. 不支持IE8及以下浏览器.效果图如下 : 在线预览   源码下载 实现的代码. html代码: <div class="wrap"> <div class="box1 box"> 1</div> <div class="box2 box">

3D HTML5 Logo标志 超炫酷旋转特效

今天又要为大家带来一款超酷的HTML5 Canvas 3D动画特效,是一款可以旋转的HTML5 Logo标志.画面上一共有两块可旋转的区域,第一是可旋转的背景,第二则是可旋转的Logo标志.Logo标志在旋转的时候还有3D的视觉效果,这一切我们都是在canvas上实现的.具体演示和实现过程可以看下文. 你也可以在这里查看在线演示 下面我们来简单分析一下实现这款3D动画的过程及其部分核心代码,主要由HTML代码以及Javascript代码组成. HTML代码: <canvas id="can