/**
* 计算气泡的布局位置
* @param textViews
*/
private void calculateRatioFrame(List<BubbleView> textViews){
if(textViews.size() == 0) return;
mRatioFrameList.clear();
double angle = 0;//记录每个气泡的角度,正上方的为0°
double grad = Math.PI * 2 / textViews.size();//梯度,每个TextView之间的角度 (Math.PI 是数学中的90°)
double rightAngle = Math.PI / 2;//一圈为360°,一共四个方向,每个方向90°,我们按照小于等于90°来计算,然后再放到相应的方向上
//cx,cy是容器的中心点,也是圆形头像的中心点,计算气泡的位置就是已cx,cy为基准来计算的
int cx = mWidth / 2;//容器中心x坐标
int cy = mHeight / 2;//容器中心y坐标
int radius = mMinSize / 2 / 2 / 2 + mMinSize / 2 / 2 ;//动态气泡的组成圆的半径
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
int a = 0,b = 0;//a是基于cx的偏移量,b是基于cy的偏移量,
//int r = mMinSize / 6 / 2;//气泡半径
for (int i = 0; i < textViews.size(); i++) {
int r = textViews.get(i).getMeasuredWidth() / 2;//计算得来//固定死的mMinSize / 6 / 2;//气泡半径
if(angle >= 0 && angle < rightAngle){ //0 - 90度是计算偏移量
//保持角度在 0 - 90
a = (int)(radius * Math.sin(Math.abs(angle % rightAngle)));
b = (int)(radius * Math.cos(Math.abs(angle % rightAngle)));
left = cx + a - r;//cx + a为气泡的中心点,要想得到left,还需减去半径r
top = cy - b - r;
right = left + 2 * r;
bottom = top + 2 * r;
}else if(angle >= rightAngle && angle < rightAngle * 2){ // 90 - 180
a = (int)(radius * Math.sin(Math.abs(angle % rightAngle)));
b = (int)(radius * Math.cos(Math.abs(angle % rightAngle)));
left = cx + b - r;
top = cy + a - r;
right = left + 2 * r;
bottom = top + 2 * r;
}else if(angle >= rightAngle * 2 && angle < rightAngle * 3){ // 180 - 270
a = (int)(radius * Math.sin(Math.abs(angle % rightAngle)));
b = (int)(radius * Math.cos(Math.abs(angle % rightAngle)));
left = cx - a - r;
top = cy + b - r;
right = left + 2 * r;
bottom = top + 2 * r;
}else if(angle >= rightAngle * 3 && angle < rightAngle * 4){ //270 - 360
a = (int)(radius * Math.sin(Math.abs(angle % rightAngle)));
b = (int)(radius * Math.cos(Math.abs(angle % rightAngle)));
left = cx - b - r;
top = cy - a - r;
right = left + 2 * r;
bottom = top + 2 * r;
}
//将计算好的left, top, right,bottom,angle保存起来
mRatioFrameList.add(new RatioFrame(left, top, right,bottom,angle));
//角度再加一个梯度值
angle += grad;
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(mImageView == null) return;
int width = mImageView.getMeasuredWidth();//计算圆形头像的宽
int height = mImageView.getMeasuredHeight();//计算圆形头像的高
//计算圆形头像的left, top, right,bottom
int left = mWidth / 2 - width / 2;
int top = mHeight / 2 - height / 2;
int right = mWidth / 2 + width / 2;
int bottom = mHeight / 2 + height / 2;
//开始布局
mImageView.layout(left,top,right,bottom);
//布局爱心动画
for (int i = 0; i < mLoveXinList.size(); i++) {
ImageView imageView = mLoveXinList.get(i);
left = mWidth / 2 + width / 4 - imageView.getMeasuredWidth() / 2;
bottom = mHeight / 2 + height / 3;
top = bottom - imageView.getMeasuredHeight();
right = left + imageView.getMeasuredWidth();
imageView.layout(left,top,right,bottom);
}
//布局所有气泡
for (int i = 0; i < mTextViews.size(); i++) {
TextView textView = mTextViews.get(i);
//RatioFrame ratioFrame = mRatioFrameList.get(i);//无动画时使用
//有动画的时候,执行期间left, top, right,bottom都在变
if(mCurrentRatioFrameList != null){
//ValueAnimator执行动画是所产生的所有气泡left, top, right,bottom
RatioFrame ratioFrame = mCurrentRatioFrameList.get(i);
textView.layout(ratioFrame.mLeft,ratioFrame.mTop,ratioFrame.mRight,ratioFrame.mBottom);
}
}
}
if(endRatioFrame.mAngle >0 && endRatioFrame.mAngle <= rightAngle){//(0 < angle <= 90)上移,左移
moveX = (int)(temp * Math.abs(Math.cos(endRatioFrame.mAngle)));//上移就应该在原本的轨迹上减去moveX
moveY = (int)(temp * Math.abs(Math.sin(endRatioFrame.mAngle)));
}else if(endRatioFrame.mAngle > rightAngle && endRatioFrame.mAngle <= rightAngle * 2){//(90 < angle <= 180)右移,上移
moveX = (int)(-temp * Math.abs(Math.cos(endRatioFrame.mAngle)));
moveY = (int)(temp * Math.abs(Math.sin(endRatioFrame.mAngle)));
}else if(endRatioFrame.mAngle > rightAngle * 2 && endRatioFrame.mAngle <= rightAngle * 3){//(180 < angle <= 2700)下移,右移
moveX = (int)(-temp * Math.abs(Math.cos(endRatioFrame.mAngle)));
moveY = (int)(-temp * Math.abs(Math.sin(endRatioFrame.mAngle)));
}else if(endRatioFrame.mAngle > rightAngle * 3 && endRatioFrame.mAngle <= rightAngle * 4 || endRatioFrame.mAngle == 0){//(270 < angle <= 360 或者 angle == 0) 左移,下移
moveX = (int)(temp * Math.abs(Math.cos(endRatioFrame.mAngle)));
moveY = (int)(-temp * Math.abs(Math.sin(endRatioFrame.mAngle)));
}
moveX = (int)(temp * Math.cos(endRatioFrame.mAngle)); moveY = (int)(temp * Math.sin(endRatioFrame.mAngle));
package com.cj.dynamicavatarview.ratio;
import android.animation.TypeEvaluator;
import android.content.Context;
import android.util.TypedValue;
import java.util.ArrayList;
import java.util.List;
/**
* Created by chenj on 2016/10/19.
*/
public class EnterRatioFrameEvaluator implements TypeEvaluator {
public static final int OFFSET_DISTANCE = 80;
private Context mContext;
private int mOffsetDistance;
public EnterRatioFrameEvaluator(Context context){
this.mContext = context;
mOffsetDistance = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,OFFSET_DISTANCE,mContext.getResources().getDisplayMetrics());
}
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
List<RatioFrame> startRatioFrameList = (List<RatioFrame>) startValue;//开始值
List<RatioFrame> endRatioFrameList = (List<RatioFrame>) endValue;//结束值
List<RatioFrame> ratioFrameList = new ArrayList<>();//产生的新值
for (int i = 0; i < endRatioFrameList.size(); i++) {
RatioFrame endRatioFrame = endRatioFrameList.get(i);
RatioFrame startRatioFrame = startRatioFrameList.get(i);
//计算left,top,right,bottom
double t = ( -2 * Math.pow(fraction,2) + 2 * fraction);//倾斜变化率
int temp = (int)((mOffsetDistance) * t);
double rightAngle = Math.PI / 2;
int moveX = 0,moveY = 0;
//让气泡上、下、左、右平移,形成弧度的平移路线
moveX = (int)(temp * Math.cos(endRatioFrame.mAngle));
moveY = (int)(temp * Math.sin(endRatioFrame.mAngle));
//重新得到left ,top,right,bottom
int left = (int)(startRatioFrame.mLeft + ((endRatioFrame.mLeft - startRatioFrame.mLeft) * fraction) - moveX);
int top = (int)(startRatioFrame.mTop + ((endRatioFrame.mTop - startRatioFrame.mTop) * fraction) - moveY) ;
int right = (int)(startRatioFrame.mRight + ((endRatioFrame.mRight - startRatioFrame.mRight) * fraction) - moveX);
int bottom = (int)(startRatioFrame.mBottom + ((endRatioFrame.mBottom - startRatioFrame.mBottom) * fraction) - moveY) ;
ratioFrameList.add(new RatioFrame(left,top,right,bottom));
}
return ratioFrameList;
}
}
ValueAnimator mAnimatorEnetr = ValueAnimator.ofObject(new EnterRatioFrameEvaluator(getContext()), getRatioFrameCenterList(mRatioFrameCenter,mRatioFrameList),mRatioFrameList);
mAnimatorEnetr.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取新的布局值
mCurrentRatioFrameList = (List<RatioFrame>) animation.getAnimatedValue();
//请求重新布局
requestLayout();
}
});
mAnimatorEnetr.setDuration(OPEN_BUBBLE_TIME);
mAnimatorEnetr.start();
/**
* 气泡由小到大缩放
* @param textViews
*/
private void scaleSmallToLarge(List<BubbleView> textViews){
// 以view中心为缩放点,由初始状态缩小到看不间
ScaleAnimation animation = new ScaleAnimation(
0.0f, 1.0f,//一点点变小知道看不见为止
0.0f, 1.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f//中间缩放
);
animation.setDuration(OPEN_BUBBLE_TIME);//要和平移的时间一致
for (int i = 0; i < textViews.size(); i++) {
//再执行动画
textViews.get(i).startAnimation(animation);
}
}
/**
* 给指定的View设置浮动效果
* @param view
* @return
*/
private AnimatorSet setAnimFloat(View view ){
List<Animator> animators = new ArrayList<>();
//getRandomDp()得到一个随机的值
ObjectAnimator translationXAnim = ObjectAnimator.ofFloat(view, "translationX", 0f,getRandomDp(),getRandomDp() , 0);
translationXAnim.setDuration(getRandomTime());
translationXAnim.setRepeatCount(ValueAnimator.INFINITE);//无限循环
translationXAnim.setRepeatMode(ValueAnimator.INFINITE);//
translationXAnim.setInterpolator(new LinearInterpolator());
translationXAnim.start();
animators.add(translationXAnim);
//
ObjectAnimator translationYAnim = ObjectAnimator.ofFloat(view, "translationY", 0f,getRandomDp(),getRandomDp() , 0);
translationYAnim.setDuration(getRandomTime());
translationYAnim.setRepeatCount(ValueAnimator.INFINITE);
translationYAnim.setRepeatMode(ValueAnimator.INFINITE);
translationXAnim.setInterpolator(new LinearInterpolator());
translationYAnim.start();
animators.add(translationYAnim);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animators);
//animatorSet.setStartDelay(delay);
animatorSet.start();
return animatorSet;
}
final AnimatorSet animatorSet = mAnimatorSetList.get(position);
for (Animator animator : animatorSet.getChildAnimations()) {
//执行到动画最后,恢复到初始位置,不然重新开始浮动的时候,会有一个闪烁的bug
if(animator.isRunning()) {
animator.end();//执行到动画最后
animator.cancel();//取消动画
}
}
/**
* 判断气泡中心点是否在图片内部
* @param view
* @param current 当前移动到的位置
* @param endRatioFrame 如果在中间,该值用于复位到原本位置
* @return
*/
private boolean isInPictureCenter(int position,View view,RatioFrame current,RatioFrame endRatioFrame){
RatioPoint centerPoint = new RatioPoint(mWidth/2,mHeight/2);
RatioPoint currentPoint = new RatioPoint(current.mLeft + ((current.mRight - current.mLeft) / 2),current.mTop + ((current.mBottom - current.mTop) / 2));
int x = Math.abs(centerPoint.x - currentPoint.x);
int y = Math.abs(centerPoint.y - currentPoint.y);
//通过勾股定理计算两点之间的距离
int edge = (int)Math.sqrt(Math.pow(x,2) + Math.pow(y,2));
int pictureRadius = mImageView.getPictureRadius();
//然后和内部图片的半斤比较,小于pictureRadius,就说明在内部
if(pictureRadius > edge){//进入到内部
if(mInnerCenterListener != null){
mInnerCenterListener.innerCenter(position,((TextView)view).getText().toString());
}
//说明到中心了,执行气泡缩放
reveseScaleView(position ,view,current,endRatioFrame);
return true;
}
return false;
}
/**
* 缩放图片(补间动画)
* @param view
* @param current 缩放后用于平移的起点
* @param endRatioFrame 缩放后用于平移的终点
*/
public void reveseScaleView(final int position , final View view, final RatioFrame current, final Object endRatioFrame) {
// 以view中心为缩放点,由初始状态缩小到看不间
ScaleAnimation animation = new ScaleAnimation(
1.0f, 0.0f,//一点点变小知道看不见为止
1.0f, 0.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f//中间缩放
);
animation.setDuration(BUBBLE_ENTER_CENTER_SCALE_TIME);
animation.setRepeatMode(Animation.REVERSE);
animation.setRepeatCount(1);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
//执行完缩放后,让气泡归位,归位结束后,执行接口回调
homingBubbleView(true,position,view, current, endRatioFrame);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
view.startAnimation(animation);
}
public interface InnerCenterListener{
//进入中心,松开归位后调用
void innerCenterHominged(int position, String text);
//进入中心,松开时调用
void innerCenter(int position, String text);
}
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有