仿支付宝收取积分的收集动画

支付宝会员积分使用支付宝支付之后会有支付积分产生,这个需要自己手动的去收集,否则不能使用。公司是做文章阅读的,目前有一个需求是需要点击一个按钮,手动的手机阅读文章的磁能分数,类似支付宝的蚂蚁森林收集水滴的效果,如下图所示:
在这里插入图片描述
点击立即收取之后需要有个类似支付宝的蚂蚁森林的收集水滴的效果,然后反转中间的按钮,把所有的积分统计出来。
下面的代码示自定义控件的具体实现:

/**
 * 收集词能的自定义动画
 * @author guotianhui
 */
public class CollectWordsLayout extends RelativeLayout {


    private int mDefaultEnergyScore;
    private String mTotalEnergyScore;
    private boolean isFlipCard = true;
    private final LayoutInflater mInflater;
    private boolean isOpenAnimation;//是否开启动画0
    private boolean isCancelAnimation;//是否销毁动画
    private boolean isInitLayout =true;
    private FrameLayout mBtnCollectWords;
    private final Random mRandom = new Random();
    private boolean isCollectWords = true;
    private ArrayList<WordEnergy> mEnergyList; //设置词能集合
    private RelativeLayout mCollectWordLayout;
    private CountScoreTextView mTvCollectScore;
    private AppCompatTextView mTvClickCollect;
    private static final int WHAT_ADD_PROGRESS = 1;
    private static final int INIT_ANIMATION = 2;
    private static final int CHANGE_RANGE = 10;  //view变化的y抖动范围
    public static final int PROGRESS_DELAY_MILLIS = 12; // 控制抖动动画执行的快慢,人眼不能识别16ms以下的
    public static final int REMOVE_DELAY_MILLIS = 1500; // 控制移除view的动画执行时间
    private AppCompatTextView mTvTotalEnergyScore,mTotalEnergy;
    private final ArrayList<Integer> mWordsEnergy = new ArrayList<>();
    private ArrayList<Point> mViewPoint = new ArrayList<>(); //创建一个界面的坐标点位置
    private OnAnimationCloseListener mOnAnimationCloseListener; // 动态收起布局的回调
    public static final int ANIMATION_SHOW_VIEW_DURATION = 500; //添加水滴时动画显示view执行的时间
    private final ArrayList<Integer> mRandomViewList = new ArrayList<>(); // 随机的词能列表
    private final ArrayList<WordsItemLayout> mViewList = new ArrayList<>();
    private final ArrayList<WordEnergy> mCollectEnergyList  = new ArrayList<>(); //收起词能的集合
    private final List<Float> mSpds = Arrays.asList(0.5f, 0.3f, 0.4f, 0.6f); //控制水滴动画的快慢
    private WordsItemLayout mWordsItemOne,mWordsItemTwo,mWordsItemThere,mWordsItemFour,mWordsItemFive,
            mWordsItemSix,mWordsItemSeven,mWordsItemEight,mWordsItemNine,mWordsItemTen,mWordsItemEleven;



    public CollectWordsLayout(@NonNull Context context) {
        this(context, null);
        initCollectWordsLayout();
    }

    public CollectWordsLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
        initCollectWordsLayout();
    }

    public CollectWordsLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mInflater = LayoutInflater.from(getContext());
        initCollectWordsLayout();
    }

    @SuppressLint("HandlerLeak")
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case WHAT_ADD_PROGRESS:
                    if (isCancelAnimation) { //根据isCancelAnimtion来标识是否退出,防止界面销毁时,再一次改变UI
                        return;
                    }
                    setWordsOffSet();  //改变View的Y轴坐标位置,实现上下移动的效果
                    mHandler.sendEmptyMessageDelayed(WHAT_ADD_PROGRESS, PROGRESS_DELAY_MILLIS);
                    break;
                case INIT_ANIMATION:
                    startAnimation();
                    break;
                default:
                    break;
            }
        }
    };

    private void initCollectWordsLayout() {
        if(isInitLayout) {
            View view = mInflater.inflate(R.layout.layout_collect_words, this, false);
            mCollectWordLayout = view.findViewById(R.id.rl_collect_words_layout);
            mWordsItemOne = view.findViewById(R.id.wil_words_item_one);
            mWordsItemTwo = view.findViewById(R.id.wil_words_item_two);
            mWordsItemThere = view.findViewById(R.id.wil_words_item_there);
            mWordsItemFour = view.findViewById(R.id.wil_words_item_four);
            mWordsItemFive = view.findViewById(R.id.wil_words_item_five);
            mWordsItemSix = view.findViewById(R.id.wil_words_item_six);
            mWordsItemSeven = view.findViewById(R.id.wil_words_item_seven);
            mWordsItemEight = view.findViewById(R.id.wil_words_item_eight);
            mWordsItemNine = view.findViewById(R.id.wil_words_item_nine);
            mWordsItemTen = view.findViewById(R.id.wil_words_item_ten);
            mWordsItemEleven = view.findViewById(R.id.wil_words_item_eleven);

            mViewList.clear(); //先清空列表,再添加数据
            mViewList.add(mWordsItemOne);
            mViewList.add(mWordsItemTwo);
            mViewList.add(mWordsItemThere);
            mViewList.add(mWordsItemFour);
            mViewList.add(mWordsItemFive);
            mViewList.add(mWordsItemSix);
            mViewList.add(mWordsItemSeven);
            mViewList.add(mWordsItemEight);
            mViewList.add(mWordsItemNine);
            mViewList.add(mWordsItemTen);
            mViewList.add(mWordsItemEleven);
            initOtherViewLayout(view); //抽取方法
            isInitLayout =false; //解决初始化两次的问题
        }
    }

    private void initOtherViewLayout(View view) {
        mBtnCollectWords = view.findViewById(R.id.fl_click_collect_words);
        mTvCollectScore = view.findViewById(R.id.tv_collect_score);
        mTvClickCollect = view.findViewById(R.id.tv_click_collect);
        mTotalEnergy = view.findViewById(R.id.tv_total_energy);
        mTvTotalEnergyScore = view.findViewById(R.id.tv_total_energy_score);
        initLayoutListener();
        addView(view);
        addShowViewAnimation(view);
        mHandler.sendEmptyMessageDelayed(INIT_ANIMATION, 200);
    }

    /**
     * 设置点击事件
     */
    private void initLayoutListener() {
        mBtnCollectWords.setOnClickListener((view) -> {
            ViewClickUtils.setViewDelaySecondsClickAble(mBtnCollectWords,2000);
            if (isCollectWords) {
                for (int i=0; i< mViewList.size(); i++) {
                    removeViewAnimation(i);
                }
                flipAnimatorXViewShow(mTvClickCollect, mTvCollectScore, 500, 0);
            }
        });
        //统计词能结束,翻转卡片
        mTvCollectScore.setOnFinishCollectListener(totalScore -> {
            mTotalEnergyScore = totalScore; //返回总的词能分数
            mDefaultEnergyScore = Integer.valueOf(totalScore);
            mTvTotalEnergyScore.setText(mTotalEnergyScore);
            if (isFlipCard) {
                isFlipCard = false;
                flipAnimatorXViewShow(mTvCollectScore, mTvClickCollect, 500, 1500);
            }
        });
    }

    /**
     * 添加显示动画
     * @param view
     */
    private void addShowViewAnimation(View view) {
        view.setAlpha(0);
        view.setScaleX(0);
        view.setScaleY(0);
        view.animate().alpha(1).scaleX(1).scaleY(1).setDuration(ANIMATION_SHOW_VIEW_DURATION).start();
    }

    /**
     * 设置所有子view的加速度
     */
    private void setViewsSpeed() {
        for (int i = 0; i < mViewList.size(); i++) {
            View view = mViewList.get(i);
            setWordsSpeed(view);
        }
    }

    /**
     * 设置View的运动速度
     * @param view
     */
    private void setWordsSpeed(View view) {
        float spd = mSpds.get(mRandom.nextInt(mSpds.size()));
        view.setTag(R.string.spd, spd);
    }

    /**
     * 设置偏移
     */
    private void setWordsOffSet() {
        for (int i = 0; i < mViewList.size(); i++) {
            View view = mViewList.get(i);
            //拿到上次view保存的速度
            float spd = (float) view.getTag(R.string.spd);
            //水滴初始的位置
            Point point = mViewPoint.get(i);
            float original = point.y;
            boolean isUp = (boolean) view.getTag(R.string.isUp);
            float translationY;
            //根据水滴tag中的上下移动标识移动view
            if (isUp) {
                translationY = view.getY() - spd;
            } else {
                translationY = view.getY() + spd;
            }
            //对水滴位移范围的控制
            if (translationY - original > CHANGE_RANGE) {
                translationY = original + CHANGE_RANGE;
                view.setTag(R.string.isUp, true);
            } else if (translationY - original < -CHANGE_RANGE) {
                translationY = original - CHANGE_RANGE;
                // FIXME:每次当水滴回到初始点时再一次设置水滴的速度,从而达到时而快时而慢
                setWordsSpeed(view);
                view.setTag(R.string.isUp, false);
            }
            view.setY(translationY);
        }
    }

    /**
     * 移除动画
     */
    private void removeViewAnimation(int i) {
        WordsItemLayout view = mViewList.get(i);
        view.clearAnimation();   //清除抖动动画
        Interpolator Interpolator = new LinearInterpolator();
        float distanceX = getTarnslationX(view);
        float distanceY = getTarnslationY(view);
        ObjectAnimator transYAnim = ObjectAnimator.ofFloat(view, "translationY", distanceY);
        ObjectAnimator transXAnim = ObjectAnimator.ofFloat(view, "translationX", distanceX);
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(view, "scaleX", 1.0f, 0.0f);
        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(view, "scaleY", 1.0f, 0.0f);
        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0.0f);

        AnimatorSet set = new AnimatorSet();
        set.setInterpolator(Interpolator);
        set.playTogether(transYAnim, transXAnim, scaleXAnim, scaleYAnim, alphaAnim);
        set.setDuration(REMOVE_DELAY_MILLIS);
        set.start();

        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                view.clearAnimation();
                addShowViewAnimation(view); //还原动画效果
                //取出原始坐标,让词能位置还原
                Point point = mViewPoint.get(i);
                float originalY = point.y;
                float originalX = point.x;
                view.setY(originalY);
                view.setX(originalX);
                view.setVisibility(View.INVISIBLE);
            }
        });
    }

    /**
     * 计算两点移动的X轴距离
     * @param view
     * @return
     */
    private float getTarnslationX(View view) {
        float viewX = view.getRight();
        float btnX = mBtnCollectWords.getRight();
        return btnX - viewX;
    }

    /**
     * 计算两点移动的Y轴距离
     * @param view
     * @return
     */
    private float getTarnslationY(View view) {
        float viewY = view.getBottom();
        float btnY = mBtnCollectWords.getBottom();
        return btnY - viewY;
    }

    /**
     * 开启水滴抖动动画
     */
    public void startAnimation() {
        if (isOpenAnimation) {
            return;
        }
        for (WordsItemLayout wordsItemLayout : mViewList) { // 添加上下移动的动画
            setViewsSpeed();
            addShowViewAnimation(wordsItemLayout);
            wordsItemLayout.setTag(R.string.isUp, false); //随机设置view动画的方向
            Point point = new Point((int) wordsItemLayout.getX(), (int) wordsItemLayout.getY());
            mViewPoint.add(point);
        }
        isOpenAnimation = true;
        isCancelAnimation = false;
        mHandler.sendEmptyMessage(WHAT_ADD_PROGRESS);
    }

    /**
     * 初始化词能数据显示
     */
    private void initWordsEnergyData() {
        if(mEnergyList.size()  >=11) {  //集合大于11时,先显示一屏的数据
            for(int i=0 ; i< 11; i++) { //先取出一屏显示
                displayWordEnergyByIndex(i,false);
            }
        }else{
            for(int i=0 ; i< mEnergyList.size(); i++) {
                initRandomArrayListByBound(i);//初始化不重复的随机数组
                displayWordEnergyByIndex(i,true);
            }
        }
    }
    /**
     * 根据角标获取显示的词能位置
     * @param i
     */
    private void displayWordEnergyByIndex(int i, boolean isRandom) {
        WordsItemLayout wordsItemLayout;
        if(isRandom){
            int randomIndex = mRandomViewList.get(i);
            wordsItemLayout = mViewList.get(randomIndex);
        }else{
            wordsItemLayout = mViewList.get(i);
        }
        WordEnergy wordEnergy = mEnergyList.get(i); //一个词能对应一个View
        wordsItemLayout.setVisibility(View.VISIBLE);
        wordsItemLayout.setCollectWord(wordEnergy.getWordName());
        wordsItemLayout.setCollectWordEnergy(wordEnergy.getWordsEnergy());
        mCollectEnergyList.add(wordEnergy); //本地保存已经显示过的数据
        mWordsEnergy.add(wordEnergy.getWordsEnergy());
    }
    /**
     * 获取一个不会重复的随机数,范围0-10
     */
    private void initRandomArrayListByBound(int randomSize) {
        int[] a = new int[randomSize];//初始化数组
        int count = 0;//记录有效的随机数个数
        while(count < a.length){
            boolean flag = true;//用来标志的变量
            int r = mRandom.nextInt(mViewList.size());
            for(int i : a){
                if(r == i){
                    flag = false;
                    break;
                }
            }
            if(flag){
                a[count] = r;
                count++;
                mRandomViewList.add(r); //把不重复的角标值放入集合
            }
        }
    }
    /**
     * 提供一个方法,判断显示过的词能集合和网络返回的词能列表是否相同
     */
    private boolean compareLocalWordsNumber(){
        if(mEnergyList.size() >mCollectEnergyList.size()){
            int otherSceenList = mEnergyList.size() - mCollectEnergyList.size();
            int secondIndex = mCollectEnergyList.size(); //取出第二屏数据的起始位置
            mWordsEnergy.clear();//清空上一次的词能
            if(otherSceenList >=11){
                for (int i = 0; i < 11; i++) {
                    showAnotherSceenWords(secondIndex, i,false);
                }
            }else {
                for (int i = 0; i < otherSceenList; i++) {
                    initRandomArrayListByBound(otherSceenList);//初始化不重复的随机数组
                    showAnotherSceenWords(secondIndex, i,true);
                }
            }
             startAnimation(); //重新开启动画
            return  true;
        }else{
            return false;
        }
    }

    /**
     * 显示其外一屏数据
     * @param secondIndex
     * @param i
     */
    private void showAnotherSceenWords(int secondIndex, int i,boolean isRandom) {
        WordsItemLayout wordsItemLayout;
        if(isRandom){
            int randomIndex = mRandomViewList.get(i);
            wordsItemLayout = mViewList.get(randomIndex);
        }else{
            wordsItemLayout = mViewList.get(i);
        }
        WordEnergy wordEnergy = mEnergyList.get(i + secondIndex);
        wordsItemLayout.setVisibility(View.VISIBLE);
        wordsItemLayout.setCollectWord(wordEnergy.getWordName());
        wordsItemLayout.setCollectWordEnergy(wordEnergy.getWordsEnergy());
        mCollectEnergyList.add(wordEnergy);
        mWordsEnergy.add(wordEnergy.getWordsEnergy());
    }

    /**
     * 销毁
     */
    private void onDestroy() {
        isCancelAnimation = true;
        mHandler.removeCallbacksAndMessages(this);
    }

    /**
     * 界面销毁时回调
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        onDestroy();
    }

    /**
     * 翻转卡片动画
     * @param oldView
     * @param newView
     * @param duringTime
     * @param delayeTime
     */
    private void flipAnimatorXViewShow(final View oldView, final View newView, final long duringTime, long delayeTime) {
        mBtnCollectWords.postDelayed(new Runnable() {
            @Override
            public void run() {
                ObjectAnimator animator1 = ObjectAnimator.ofFloat(oldView, "rotationX", 0, 90);
                final ObjectAnimator animator2 = ObjectAnimator.ofFloat(newView, "rotationX", -90, 0);
                animator2.setInterpolator(new OvershootInterpolator(2.0f));
                animator1.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                    }
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        oldView.setVisibility(View.GONE);
                        animator2.setDuration(duringTime).start();
                        newView.setVisibility(View.VISIBLE);
                    }
                    @Override
                    public void onAnimationCancel(Animator animation) {
                    }
                    @Override
                    public void onAnimationRepeat(Animator animation) {
                    }
                });
                animator2.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        if (isCollectWords) {
                            isFlipCard = true;
                            isCollectWords = false;
                            mTvCollectScore.setTotalScore(mDefaultEnergyScore); //初始化词能
                            mTvCollectScore.setCountScoreList(mWordsEnergy);//添加能量值
                        }else{
                            isFlipCard = true;
                            isCollectWords = true;
                            boolean isCompareLocal = compareLocalWordsNumber();//重新初始化词能布局
                            if(!isCompareLocal){
                                if(ObjectUtils.isNotEmpty(mOnAnimationCloseListener)){  //动态收起布局
                                    isCancelAnimation = true;
                                    mOnAnimationCloseListener.onAnimationClose(); //回调动态收起布局
                                    ArrayList<String> arrayList = new ArrayList<>();
                                    for(WordEnergy wordEnergy : mEnergyList){
                                        arrayList.add(wordEnergy.getWordName());
                                    }
                                    mOnAnimationCloseListener.onAddCollectWordsToTagCloud(arrayList);
                                }
                            }
                        }
                    }
                });
                animator1.setDuration(duringTime).start();
            }
        }, delayeTime);
    }
    /**
     * 提供一个方法接收词能集合,并初始化词能值
     */
    public void setWordsEnergyAndTotalScore(ArrayList<WordEnergy> energyList, int totalScore){
        this.mEnergyList = energyList;
        this.mDefaultEnergyScore = totalScore;
        //显示数据
        initWordsEnergyData();
    }
    /**
     * 动态收起布局方法
     * @param view
     */
    public void animateCloseLayout(final RelativeLayout view) {
        view.post(() ->{
            int origHeight = view.getHeight();
            ValueAnimator animator = createDropAnimator(view, origHeight, PhoneSystemUtils.dp2px(90,getContext()));
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mCollectWordLayout.clearAnimation();
                    mCollectWordLayout.removeAllViews();
                    mCollectWordLayout.addView(mTotalEnergy);
                    mCollectWordLayout.addView(mTvTotalEnergyScore);
                    mTotalEnergy.setVisibility(View.VISIBLE);
                    mTvTotalEnergyScore.setVisibility(View.VISIBLE);
                    mTvTotalEnergyScore.setText(mTotalEnergyScore);
                    mCollectWordLayout.setBackground(getResources().getDrawable(R.drawable.ic_total_score_bg));
                }
            });
            animator.start();
        });
    }
    /**
     * 动态改变布局高度的属性动画
     * @param view
     * @param start
     * @param end
     * @return
     */
    private ValueAnimator createDropAnimator(final View view, int start, int end) {
        ValueAnimator animator = ValueAnimator.ofInt(start, end);
        animator.addUpdateListener((animation1) ->{
            int value = (int) animation1.getAnimatedValue();
            ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
            layoutParams.height = value;
            view.setLayoutParams(layoutParams);
        });
        return animator;
    }

    /**
     * 设置回调监听
     * @param listener
     */
   public void setOnAnimationCloseLayout(OnAnimationCloseListener listener){
        this.mOnAnimationCloseListener = listener;
   }
    /**
     * 提供一个回调接口,动态的收起布局
     */
    public interface OnAnimationCloseListener{
        void onAnimationClose();
        void onAddCollectWordsToTagCloud(List<String> tagsList);
    }
}

自定义控件的布局文件实现:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_collect_words_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_ffe5c4_solid_r10">

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/tv_total_energy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="总词能"
        android:textColor="#fff29f87"
        android:textSize="15sp"
        android:visibility="gone"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/dp_15"/>
    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/tv_total_energy_score"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="8,345"
        android:textColor="#fff29f87"
        android:textSize="24sp"
        android:visibility="gone"
        android:layout_marginTop="@dimen/dp_8"
        android:layout_below="@+id/tv_total_energy"
        android:layout_centerHorizontal="true"/>
    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_there"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:visibility="invisible"
        android:layout_marginTop="@dimen/dp_30"
        android:layout_marginStart="@dimen/dp_22"/>
    <FrameLayout
        android:id="@+id/fl_click_collect_words"
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="@dimen/dp_25"
        android:layout_below="@+id/wil_words_item_there"
        android:background="@drawable/bg_collect_words_r75">
        <com.fenji.read.module.student.widget.CountScoreTextView
            android:id="@+id/tv_collect_score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            android:gravity="center"
            android:layout_gravity="center"
            android:background="@drawable/bg_collect_words_r60"
            android:textColor="@color/white"/>
        <android.support.v7.widget.AppCompatTextView
            android:id="@+id/tv_click_collect"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="点击领取"
            android:textSize="14sp"
            android:gravity="center"
            android:layout_gravity="center"
            android:background="@drawable/bg_collect_words_r60"
            android:textColor="@color/white"/>
    </FrameLayout>
   <com.fenji.read.module.student.widget.WordsItemLayout
         android:id="@+id/wil_words_item_one"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/dp_12"
         android:visibility="invisible"
         android:layout_marginStart="@dimen/dp_12"/>
    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_two"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/wil_words_item_one"
        android:layout_marginTop="@dimen/dp_15"
        android:visibility="invisible"
        android:layout_marginStart="@dimen/dp_15"/>

    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_four"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toStartOf="@+id/wil_words_item_five"
        android:layout_marginTop="@dimen/dp_20"
        android:visibility="invisible"
        android:layout_marginEnd="@dimen/dp_15"/>
    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_five"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_marginTop="@dimen/dp_15"
        android:visibility="invisible"
        android:layout_marginEnd="@dimen/dp_15"/>
    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_six"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/wil_words_item_one"
        android:layout_marginTop="@dimen/dp_12"
        android:visibility="invisible"
        android:layout_marginStart="@dimen/dp_12"/>
    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_seven"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/wil_words_item_six"
        android:layout_below="@+id/wil_words_item_two"
        android:layout_marginTop="@dimen/dp_15"
        android:visibility="invisible"
        android:layout_marginStart="@dimen/dp_15"/>
    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_eight"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/wil_words_item_four"
        android:layout_toStartOf="@+id/wil_words_item_nine"
        android:layout_marginTop="@dimen/dp_15"
        android:visibility="invisible"
        android:layout_marginEnd="@dimen/dp_15"/>
    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_nine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_below="@+id/wil_words_item_five"
        android:layout_marginTop="@dimen/dp_15"
        android:visibility="invisible"
        android:layout_marginEnd="@dimen/dp_15"/>


    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_ten"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_marginBottom="@dimen/dp_20"
        android:visibility="invisible"
        android:layout_below="@+id/wil_words_item_seven"
        android:layout_marginTop="@dimen/dp_15"
        android:layout_marginStart="40dp"/>
    <com.fenji.read.module.student.widget.WordsItemLayout
        android:id="@+id/wil_words_item_eleven"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:visibility="invisible"
        android:layout_below="@+id/wil_words_item_nine"
        android:layout_marginTop="@dimen/dp_15"
        android:layout_marginBottom="@dimen/dp_20"
        android:layout_marginEnd="40dp"/>
</RelativeLayout>

实例化自定义控件之后,需要手动调用它的方法把词能数据传进去。代码如下:

  ArrayList<WordEnergy> wordEnergies = new ArrayList<>();
        for (int i = 0; i <14; i++){
            WordEnergy wordEnergy = new WordEnergy("凤毛麟角",1);
            wordEnergies.add(wordEnergy);
        }
        mCollectWordsLayout.setWordsEnergyAndTotalScore(wordEnergies,50);

数据实体对象代码:

/**
 * 词云养成的词能数据对象
 * @author guotianhui
 */
public class WordEnergy{

    public WordEnergy(String name,int energy){
        this.wordName = name;
        this.wordsEnergy =energy;
    }
    private String wordName;
    private int wordsEnergy;

    public String getWordName() {
        return wordName;
    }

    public void setWordName(String wordName) {
        this.wordName = wordName;
    }

    public int getWordsEnergy() {
        return wordsEnergy;
    }

    public void setWordsEnergy(int wordsEnergy) {
        this.wordsEnergy = wordsEnergy;
    }
}

最后我把实现积分统计的自定义控件给贴上代码,代码直接可以用,希望对您有用,谢谢!


/**
 * 动态计分的TextView
 * @author guotianhui
 */
public class CountScoreTextView extends AppCompatTextView{

    int scoreIndex = 0; //集合取值的角标
    private Timer mTimer; //定时计数器
    private int TOTAL_SCORE = 0; //获取的总词能
    private ArrayList<Integer> mScoreList; //词能集合
    private OnFinishCollectWords mOnFinishCollectListener;


    public CountScoreTextView(Context context) {
        super(context);
    }

    public CountScoreTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CountScoreTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 创建一个Handler,不断发送消息让Textview的分数累加,直到完成
     */
    @SuppressLint("HandlerLeak")
    private final Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 100:
                    if(msg.arg1 >0) {
                        int score = TOTAL_SCORE + msg.arg1;
                        setText(String.valueOf(score));
                        TOTAL_SCORE = score;
                        if(ObjectUtils.isNotEmpty(mOnFinishCollectListener)){  //回传总词能
                            mOnFinishCollectListener.onFinishCollect(String.valueOf(score));
                        }
                    }
                    break;
                default:{

                        }
                        break;
            }
        }
    };

    /**
     * 创建一个定时任务,循环把集合中的数值取出,并发送消息
     */
    public void startCountScore(){
        if(mTimer == null) {
            mTimer = new Timer();
            mTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if(mScoreList != null && mScoreList.size() >= scoreIndex) {
                        final Message message = new Message();
                        message.what = 100;
                        message.arg1 = getCountScoreListItem(scoreIndex);
                        mHandler.sendMessage(message);
                        scoreIndex++;
                    }else{//取完所有数值之后,停止计数并清空集合和重置角标
                        stopCountScore();
                        scoreIndex =0;
                    }
                }
            }, 0, 30);
        }
    }
    /**
     * 提供一个方法接收需要添加的数字集合
     */
    public void setCountScoreList(ArrayList<Integer> scoreList){
         this.mScoreList = scoreList;
         startCountScore();
    }

    /**
     * 根据角标获取到集合中的能量值并返回
     * @param scoreIndex
     * @return
     */
    public int getCountScoreListItem(int scoreIndex) {
      if(mScoreList!=null && mScoreList.size() > scoreIndex){
          return mScoreList.get(scoreIndex);
       }else {
          return 0;
      }
    }
    /**
     * 设置计数的起始分数
     * @param totalScore
     */
    public void setTotalScore(int totalScore) {
        this.TOTAL_SCORE = totalScore;
        setText(String.valueOf(TOTAL_SCORE));
    }

    /**
     * 停止计数
     */
    public void stopCountScore(){
        if(ObjectUtils.isNotEmpty(mTimer)) {
            mTimer.cancel();
            mTimer = null; //把计数器释放,下次进来重新创建
        }
    }
    /**
     * 提供一个方法设置回调监听
     */
    public void setOnFinishCollectListener(OnFinishCollectWords listener){
        this.mOnFinishCollectListener = listener;
    }
    /**
     * 提供一个回调接口,收集完词能翻转卡片
     */
    public interface OnFinishCollectWords{
         void onFinishCollect(String totalScord);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值