您的位置:首页 > 移动开发 > Android开发

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

2018-03-14 17:05 295 查看

仿网易星球浮动小球

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

先看看需要实现的效果:



需求分析:

数据集合可能是int、double、float等类型

小球位置随机

没有数据时只有一个默认小球,位置固定

小球上下抖动,点击向上运动消失

实现分析:

小球随机的位置固定在父view的宽高范围内

可以在初始化和点击时判断集合是否为空从而显示默认小球

补间动画实现抖动、属性动画实现点击上滑消失(纯属个人习惯,没有规定动画类型)

实现步骤:

FloatView

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

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@mipmap/star_bg">
</RelativeLayout>




小球布局

<TextView
android:id="@+id/float_view"
android:layout_width="35dp"
android:layout_height="35dp"
android:gravity="center"
android:text="0.01234"
android:textSize="6dp"
android:textColor="#ffffff"
android:background="@drawable/shape_circle">
</TextView>




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

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位置并添加



子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);


添加子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<? extends Number> 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'
}


在布局文件中使用

<com.smoke.zhangchen.floatviewlib.FloatView
android:id="@+id/float_view"
android:layout_width="match_parent"
android:layout_height="wrap_content
app:childTextColor="#ff0000"
app:defaultViewText="正在生成中"
app:chidTextSize="6sp"
app:parentViewBackground="@mipmap/star_bg"
app:childViewBackground="@drawable/shape_circle">


childTextColor:小球文字颜色大小,默认白色

defaultViewText:默认小球显示文字

parentViewBackground:整体背景

childViewBackground:小球背景

chidTextSize:小球文字大小,默认6sp

设置数据

当前数据支持int、long、float、double

List<Float> 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(MainActivit
9195
y.this, "当前是第"+position+"个,其值是"+value.floatValue(), Toast.LENGTH_SHORT).show();
}
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: