【Android自定义控件】之仿网易星球浮动小球

仿网易星球浮动小球

读呗开发过程中遇到新需求,类似于网易星球收集黑钻的界面,考虑到可能也有人会使用,索性封装成库,后面好移植使用

先看看需要实现的效果:

需求分析:

  1. 数据集合可能是int、double、float等类型
  2. 小球位置随机
  3. 没有数据时只有一个默认小球,位置固定
  4. 小球上下抖动,点击向上运动消失

实现分析:

  1. 小球随机的位置固定在父view的宽高范围内
  2. 可以在初始化和点击时判断集合是否为空从而显示默认小球
  3. 补间动画实现抖动、属性动画实现点击上滑消失(纯属个人习惯,没有规定动画类型)

实现步骤:

FloatView

父控件使用Relativelayout(背景可以先指定,后面已经抽取出来可以自定义)



【Android自定义控件】之仿网易星球浮动小球_第1张图片

小球布局



子控件

上面布局都是暂定的,后面封装的时候都保留了接口

1、定义构造方法

 public FloatView(Context context) {
       this(context,null);
       mcontext = context;
     }

 public FloatView(Context context, AttributeSet attrs) {
       super(context, attrs);
       mcontext = context;  
     }

public FloatView(Context context, AttributeSet attrs, int defStyleAttr) {
       this(context, attrs);
       mcontext = context;
    }

2、初始化默认小球

LayoutParams params = new LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);
defaultView = (TextView) LayoutInflater.from(mcontext).inflate(R.layout.view_float, this, false); params.addRule(RelativeLayout.CENTER_IN_PARENT);       
if (mFloat.size() != 0){
    defaultView.setVisibility(GONE);
}
addView(defaultView,params);

3、设置子view位置并添加

【Android自定义控件】之仿网易星球浮动小球_第2张图片

  1. 子View随机坐标范围(保证不能出parentView的边界)

        Random randomX = new Random();
        Random randomY = new Random();
        float x = randomX.nextFloat() * (parentWidth - childView.getMeasuredWidth());
        float y = randomY.nextFloat() * (parentHeight - childView.getMeasuredHeight());
        childView.setX(x);
        childView.setY(y);
    
  2. 添加子View

    for (int i = 0; i < mFloat.size(); i++) {
        TextView floatview = (TextView) LayoutInflater.from(mcontext).inflate(R.layout.view_float, this, false);
        setChildViewPosition(floatview);
        floatview.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        addView(floatview);
    }
    

5、设置子View抖动动画

  Animation anim = new TranslateAnimation(0,0,-10,20);
  anim.setInterpolator(new AccelerateDecelerateInterpolator());
  anim.setDuration(ANIMATION_TIME);
  anim.setRepeatCount(Integer.MAX_VALUE);
  anim.setRepeatMode(Animation.REVERSE);//反方向执行
  view.startAnimation(anim);

6、点击移除(使用回调接口暴露方法,并判断是否是数据集合是否为空以显示默认子View)

    alueAnimator animator = ValueAnimator.ofFloat(parentHeight,0);
    animator.setDuration(1000);
    animator.setInterpolator(new LinearInterpolator());
    //动画更新的监听
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float Value = (float) animation.getAnimatedValue();

            view.setAlpha(Value/parentHeight);
            view.setTranslationY(view.getY()-(parentHeight-Value));
        }
    });
    animator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            removeView(view);
        }
    });
    animator.start();

设置回调(详情见源码):

  mListener.itemClick((int)view.getTag(),mFloat.get((int)view.getTag()));

实现效果图:

难点分析:

1、获取的宽高为0?
view绘制过程中measure的时间和Activity的生命周期不能保持一致,所以可能在onCreate()中获取的宽高为0;
解决办法:使用post()

post(new Runnable() {
      @Override
       public void run() {
           init();
       }
});

2、子View的属性为wrap_content,获取的宽高为0,?
在获取的宽高的时候,先指定测量规则

int width = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
parentView.measure(width,height);
parentHeight = parentView.getMeasuredHeight();
parentWidth = parentView.getMeasuredWidth();

3、传输数据固定?
这里list使用Number类型的泛型,可以指定为int、float、double、long

public void setList(List list){
    ...
    //回调里
    mListener.itemClick((int)view.getTag(),mFloat.get((int)view.getTag()));
}

封装

GIthub地址:StarFloatView

使用方法:

在工程目录的build.gradle中添加JitPack.io的代码仓库地址

allprojects {
  repositories {
    ...
    maven { url 'https://jitpack.io' }
  }
}

项目目录中的build.gradle中添加依赖

ependencies {
    compile 'com.github.ErChenZhang:StarFloatView:v1.1'
}

在布局文件中使用

     
  1. childTextColor:小球文字颜色大小,默认白色
  2. defaultViewText:默认小球显示文字
  3. parentViewBackground:整体背景
  4. childViewBackground:小球背景
  5. chidTextSize:小球文字大小,默认6sp

    设置数据

    当前数据支持int、long、float、double
     List list = new ArrayList<>();
        list.add((float) 1.245);
        list.add((float) 1.567);
        list.add((float) 0.261);
        floatview.setList(list);
    

小球点击回调(value.floatValue()对应传入的list类型)

floatview.setOnItemClickListener(new FloatView.OnItemClickListener() {
    @Override
     public void itemClick(int position, Number value) {
         Toast.makeText(MainActivity.this, "当前是第"+position+"个,其值是"+value.floatValue(), Toast.LENGTH_SHORT).show();
        }
});

你可能感兴趣的:(自定义控件)