Effect:

Implementation idea:

1.ViewAnimator idea Uses ViewAnimator’s own features to realize animation switch on the in-process sub-view

In this way, we can define a container, inherit FrameLayout, and add FrameLayout to the itemView according to the number of data. Animation is done by making an outgoing Finagan statement for the current itemView and an entry animation for the next itemView, using the Handle to implement deferred rotation

ViewFlipper is the same as ViewAnimator, but the ViewFlipper is more flexible. Here we dynamically add an itemView to the ViewFlipper based on the data flow

5. Customize textView ideas

In fact, this idea is easy to understand, we inherit textView, and then in onDraw draw their own words, do their own animation, animation idea is to first move the previous text to the top, and then draw the next text, from the beginning of the following has been moved to the middle

ViewAnimator ideas

A ViewAnimator is a viewGroup that can animate a child view. In XML layout, ViewAnimator is used as a container to write views in rotation. As many views are written, there are as many views in rotation. Then, animation for switching is set and handle is used as timing delay rotation. Call viewanimator.onNext to switch to the next view

Implementation idea:

1. Declare the layout hierarchy in the Layout XML:

 <ViewAnimator
        android:layout_width="match_parent"
        android:layout_height="200dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Welcome"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Test"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="This Procedure"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="!!!!!!!!"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="hello,world"/>
    </ViewAnimator>
Copy the code

2. Code type setting switching animation

viewAnimator.setOutAnimation(this.R.anim.slide_out_up);
viewAnimator.setInAnimation(this.R.anim.slide_in_down);
Copy the code

3. Handle delay loop displays the next one

      public void showNext(a) {
        viewAnimator.showNext();
    }

    public void showPrevious(a) {
        viewAnimator.showPrevious();
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (autoPlayFlag) {
                showNext();
            }
            handler.sendMessageDelayed(newMessage(), TIME_INTERVAL); }};Copy the code

We can just send the Handle event at the desired location

Using ViewAnimator is a bit as obvious as being sure

  • Advantages: Easy to use, no difficulty

  • Disadvantages: The number of views is fixed in XML. In order to be compatible with different data volumes, we need to develop ViewAnimator twice

Customize the viewGroup idea

In this way, we define a container, inherit FrameLayout, and add FrameLayout to the itemView according to the number of items in the container. We animate the FrameLayout by making a finagan statement to the current itemView. Do an entry animation for the next itemView and use handle to implement deferred rotation

Ideas as follows

1. Add the corresponding number of ItemViews when setting the data

    public void setNoticeList(List<String> list) {

        / / create a TextView
        for (int i = 0; i < list.size(); i++) {
            TextView textView = createTextView(list.get(i));
            mNoticeList.add(textView);
            addView(textView);
        }
        // Displays the first bulletin
        mCurrentNotice = 0;
        mNoticeList.get(mCurrentNotice).setVisibility(VISIBLE);
        // Start multicast
        start();
    }

    private TextView createTextView(String text) {
        if (mLayoutParams == null) {
            mLayoutParams = new LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            mLayoutParams.gravity = Gravity.CENTER_VERTICAL;
        }

        TextView textView = new TextView(getContext());
        textView.setLayoutParams(mLayoutParams);
        textView.setSingleLine();
        textView.setEllipsize(TextUtils.TruncateAt.END);
        textView.setTextColor(mTextColor);
        textView.setVisibility(GONE);
        textView.setText(text);
        // If font size is set, if font size is null.
        if (mTextSize > 0) {
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
        }
        return textView;
    }
Copy the code

2. Animate the itemView toggle in Handle

     class NoticeRunnable implements Runnable {
        @Override
        public void run(a) {
            // Hide the current textView
            TextView currentView = mNoticeList.get(mCurrentNotice);
            currentView.setVisibility(GONE);
            if(mExitAnimSet ! =null) {
                currentView.startAnimation(mExitAnimSet);
            }
            mCurrentNotice++;
            if(mCurrentNotice >= mNoticeList.size()) {
                mCurrentNotice = 0;
            }

            // Displays the next TextView
            TextView nextView = mNoticeList.get(mCurrentNotice);
            nextView.setVisibility(VISIBLE);
            if(mEnterAnimSet ! =null) {
                nextView.startAnimation(mEnterAnimSet);
            }
            mHandler.postDelayed(this, mNoticeDuration); }}private void createEnterAnimation(a) {
        mEnterAnimSet = new AnimationSet(false);
        TranslateAnimation translateAnimation =
                new TranslateAnimation(0.0.0.0, TranslateAnimation.RELATIVE_TO_PARENT, 1f,
                        TranslateAnimation.RELATIVE_TO_SELF, 0f);
        AlphaAnimation alphaAnimation = new AlphaAnimation(0f.1f);
        mEnterAnimSet.addAnimation(translateAnimation);
        mEnterAnimSet.addAnimation(alphaAnimation);
        mEnterAnimSet.setDuration(DEFAULT_ANIMATION_DURATION);
    }

    private void createExitAnimation(a) {
        mExitAnimSet = new AnimationSet(false);
        TranslateAnimation translateAnimation =
                new TranslateAnimation(0.0.0.0, TranslateAnimation.RELATIVE_TO_SELF, 0f,
                        TranslateAnimation.RELATIVE_TO_PARENT, -1f);
        AlphaAnimation alphaAnimation = new AlphaAnimation(1f.0f);
        mExitAnimSet.addAnimation(translateAnimation);
        mExitAnimSet.addAnimation(alphaAnimation);
        mExitAnimSet.setDuration(DEFAULT_ANIMATION_DURATION);
    }
Copy the code

This is the best way to write, but I do not recommend doing so, the poor foundation of some problems, and Google provides us with some implementation, we do not have to implement their own, anyway, it will take some time to write

ViewFlipper ideas

The ViewFlipper idea is like a combination of 1 and 2, and the ViewFlipper has a little bit more control over the animation, so we dynamically add an itemView to the ViewFlipper, basically the same idea, but the difference is that we use different containers

A mature library is recommended:

  • TextBannerView

This library is very perfect, but also to meet your common needs, can be used directly, we see the picture to understand

Ideas as follows

He’s got a custom ViewGroup that inherits from a RelativeLayout, and when the view is initialized, he adds a ViewFlipper, and that’s all he’s gonna do

1. The ViewFlipper is added during the initialization of a custom ViewGroup

    /** Initialize the controller */
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {

        mViewFlipper = new ViewFlipper(getContext());/ / new a ViewAnimator
        mViewFlipper.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        addView(mViewFlipper);
        startViewAnimator();
        // Set the click event
        mViewFlipper.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = mViewFlipper.getDisplayedChild();// The index position of the currently displayed subview
                if(mListener! =null){ mListener.onItemClick(mDatas.get(position),position); }}});Copy the code

2. Add an itemView based on the data

      /** Set the data set */
    public void setDatas(List<String> datas){
        this.mDatas = datas;
        if (DisplayUtils.notEmpty(mDatas)){
            mViewFlipper.removeAllViews();
            for (int i = 0; i < mDatas.size(); i++) {
                TextView textView = new TextView(getContext());
                textView.setText(mDatas.get(i));
                // Set your text style arbitrarily, here
                textView.setSingleLine(isSingleLine);
                textView.setTextColor(mTextColor);
                textView.setTextSize(mTextSize);
                textView.setGravity(mGravity);

                mViewFlipper.addView(textView,i);// Add a child view and identify its location}}}Copy the code

3. Add animations

    /** * Set to enter animation and leave animation@paramInAnimResId Enter the animation resID *@paramOutAnimResID Leaves the animation resID */
    private void setInAndOutAnimation(@AnimRes int inAnimResId, @AnimRes int outAnimResID) {
        Animation inAnim = AnimationUtils.loadAnimation(getContext(), inAnimResId);
        inAnim.setDuration(animDuration);
        mViewFlipper.setInAnimation(inAnim);

        Animation outAnim = AnimationUtils.loadAnimation(getContext(), outAnimResID);
        outAnim.setDuration(animDuration);
        mViewFlipper.setOutAnimation(outAnim);
    }
Copy the code

After that, I use Handle to do the delay loop. The above is copied several times, but here I do not want to copy again. It is very simple to type the source code, and we can read it directly.

There is no need to add a viewGroup to the top layer of the library. You can inherit the ViewFlipper directly

Custom textView ideas

Instead of inheriting a textView, we can inherit a view, as long as we don’t support wrap_content. The core is the animation that you draw in onDraw.

In this example, ValueAnimator is not used. Instead, it redraws every px change, which is not considered performance.

Implementation approach

1. Determine the zero bound point from which the text exits the screen

// Get the size of the text matrix
Rect indexBound = new Rect();
mPaint.getTextBounds(text, 0, text.length(), indexBound);

// Center the text to draw the Y coordinate
my = mHeight  / 2 - (bound.top + bound.bottom) / 2

// Move the text to the top
mY == 0 - bound.bottom

// Move the text to the bottom
mY = mHeight  - indexBound.top;
Copy the code

2. Draw in onDraw

         // The text is drawn first at the bottom, and mY starts = 0
        if (mY == 0) {
            mY = getMeasuredHeight() - indexBound.top;
        }

        // When the text moves to the top, change the data and move the text to the bottom
        if (mY == 0 - indexBound.bottom) {
            Log.i(TAG, "onDraw: " + getMeasuredHeight());
            mY = getMeasuredHeight() - indexBound.top;// return to bottom
            mIndex++;// Change the next set of data
        }

        // Stop handle's redraw task when the text moves to the middle and start again after a standard delay
        if (mY == getMeasuredHeight() / 2 - (indexBound.top + indexBound.bottom) / 2) {
            isMove = false;// Stop moving
            // Handle starts redrawing after notifying standard time
        }

        // After processing Y coordinates, start drawing text
        canvas.drawText(font, 0, font.length(), 10, mY, mPaintFront);

        // Finally move 1 px to achieve the animation effect
        mY -= 1
Copy the code

The point here is to redraw every px to ensure the continuity of the animation, but it takes 16 ms for the system to draw a frame, so redrawing at a high frequency is not optimal