1. 程式人生 > >Android 自定義懸浮小球

Android 自定義懸浮小球

第一次自己自定義控制元件,看了別人的控制元件,自己模仿出來一個新的,這是精簡版,拓展性很差,文章最後將完全版程式碼附上

效果和支付寶收能量,網易星球首頁鑽石一樣

先上效果圖

1.繼承 Relativelayout

public MyView(Context context)
public MyView(Context context, AttributeSet attrs)

2.在attrs中,定義屬性

<declare-styleable name="MyView">
    <attr name="cicleWidth" format="dimension" />
    <attr name="myViewWidth" format="dimension" />
    <attr name="myViewHeight" format="dimension" />
</declare-styleable>

3.在xml中,要加xmlns:app="http://schemas.android.com/apk/res-auto"

<com.luo.hellocustom.MyView
    android:id="@+id/myView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:cicleWidth="35dp"
    />

4.程式碼中,拿到屬性值

TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MyView);
parentWidth = typedArray.getDimension(R.styleable.MyView_myViewWidth, getScrWidth());
parentHeight = typedArray.getDimension(R.styleable.MyView_myViewHeight, getScrHeight());

拿到控制元件寬度,getScrWidth()是我們自己預設設定的值

5.給控制元件新增小球

寫一個方法setList();在Activity中直接呼叫,等於初始化資料

//設定資料新增子小球
public void setList(List<? extends Number> list) {
    this.mFloat = list;
    //使用post方法確保在UI載入完的情況下 呼叫init() 避免獲取到的寬高為0
    post(new Runnable() {
        @Override
        public void run() {
            init();
        }
    });
}

使用post是為了可以拿到寬高,否則為0,在post之前就需要

view = LayoutInflater.from(mContext).inflate(R.layout.view_float, this, false);

否則也拿不到值

6.小球的出現使用隨機數,生成xy

Random randomX = new Random();
Random randomY = new Random();
float x = randomX.nextFloat() * (parentWidth - view.getWidth()/2);
float y = randomY.nextFloat() * (parentHeight - view.getWidth()/2);
view.setX(x);
view.setY(y);

取值在,父控制元件的寬度減小球半徑

7,動畫,小球出現時動畫(漸變)

view.setAlpha(0);
view.setScaleX(0);
view.setScaleY(0);
view.animate().alpha(1).scaleX(1).scaleY(1).setDuration(2000).start();

8.小球的點選事件,我們可以加個回撥

public static interface onclickItemListen{
    public void onclick(View view,int postion);
}

private onclickItemListen onclickItemListen;

public void setOnclickItemListen(MyView.onclickItemListen onclickItemListen) {
    this.onclickItemListen = onclickItemListen;
}
view.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        removeFloatAnim(v);
        if (onclickItemListen != null) {
            onclickItemListen.onclick(v,i);
        }
    }
});

9.小球出現後浮動動畫,動畫(上下位移)

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

10.小球點選後,移除動畫(位移)

private void removeFloatAnim(final View view) {
    ValueAnimator 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();
            Log.d(TAG, "onAnimationUpdate: " + view.getTranslationY());
            Log.d(TAG, "onAnimationUpdate: " + view.getY());
            view.setAlpha(Value / parentHeight);
            view.setTranslationY(view.getY() - (parentHeight - Value));
        }
    });
    animator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            removeView(view);
        }
    });
    animator.start();
}

11.為了小球不出現同一位置且重合,需要遞迴

private void addNewPosition(List<Bean> allPostion, View childView) {
    Random randomX = new Random();
    Random randomY = new Random();
    float x = randomX.nextFloat() * (parentWidth - 70 - childView.getMeasuredWidth());
    float y = randomY.nextFloat() * (parentHeight - 70 - childView.getMeasuredWidth());
    boolean flag = false;
    if (allPostion.size() == 0) {
        allPostion.add(new Bean(x, y));
    }
    for (Bean bean : allPostion) {
        float x1 = bean.getX();
        float y1 = bean.getY();

        if (x > (x1 + 140) || y > (y1 + 140) || x < (x1 - 140) || y < (y1 - 140)) {
        } else {
            flag = true;
        }
    }
    if (!flag) {
        allPostion.add(new Bean(x, y));
        return;
    } else {
        addNewPosition(allPostion, childView);
    }
}

12.分成兩撥顯示,第一撥點選完以後,出現第二波

public void notifychangeAll(List<? extends Number> list) {
    allPostion.clear();
    this.mFloat = list;
    //使用post方法確保在UI載入完的情況下 呼叫init() 避免獲取到的寬高為0
    post(new Runnable() {
        @Override
        public void run() {
            centerView.clearAnimation();
            centerView.setVisibility(GONE);
            addChidView();
        }
    });
}

和初始化一樣,不過要去掉存放位置的list

ok,最終就完成了,因為時間有限這只是簡版,拓展性不是很大