com.chenupt.springindicator.SpringIndicator.java Source code

Java tutorial

Introduction

Here is the source code for com.chenupt.springindicator.SpringIndicator.java

Source

/*
 * Copyright 2015 chenupt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.chenupt.springindicator;

import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

import com.wind.gifassistant.R;

/**
 * Created by chenupt@gmail.com on 2015/1/31. Description : Tab layout container
 */
public class SpringIndicator extends FrameLayout {

    private static final int INDICATOR_ANIM_DURATION = 3000;

    private float acceleration = 0.5f;
    private float headMoveOffset = 0.6f;
    private float footMoveOffset = 1 - headMoveOffset;
    private float radiusMax;
    private float radiusMin;
    private float radiusOffset;

    private float textSize;
    private int textColorId;
    private int textBgResId;
    private int selectedTextColorId;
    private int indicatorColorId;
    private int indicatorColorsId;
    private int[] indicatorColorArray;

    private LinearLayout tabContainer;
    private SpringView springView;
    private com.ryanharter.viewpager.ViewPager viewPager;

    private List<TextView> tabs;

    private ViewPager.OnPageChangeListener delegateListener;
    private TabClickListener tabClickListener;
    private ObjectAnimator indicatorColorAnim;

    public SpringIndicator(Context context) {
        this(context, null);
    }

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

    private void initAttrs(AttributeSet attrs) {
        textColorId = R.color.si_default_text_color;
        selectedTextColorId = R.color.si_default_text_color_selected;
        indicatorColorId = R.color.si_default_indicator_bg;
        textSize = getResources().getDimension(R.dimen.si_default_text_size);
        radiusMax = getResources().getDimension(R.dimen.si_default_radius_max);
        radiusMin = getResources().getDimension(R.dimen.si_default_radius_min);

        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.SpringIndicator);
        textColorId = a.getResourceId(R.styleable.SpringIndicator_siTextColor, textColorId);
        selectedTextColorId = a.getResourceId(R.styleable.SpringIndicator_siSelectedTextColor, selectedTextColorId);
        textSize = a.getDimension(R.styleable.SpringIndicator_siTextSize, textSize);
        textBgResId = a.getResourceId(R.styleable.SpringIndicator_siTextBg, 0);
        indicatorColorId = a.getResourceId(R.styleable.SpringIndicator_siIndicatorColor, indicatorColorId);
        indicatorColorsId = a.getResourceId(R.styleable.SpringIndicator_siIndicatorColors, 0);
        radiusMax = a.getDimension(R.styleable.SpringIndicator_siRadiusMax, radiusMax);
        radiusMin = a.getDimension(R.styleable.SpringIndicator_siRadiusMin, radiusMin);
        a.recycle();

        if (indicatorColorsId != 0) {
            indicatorColorArray = getResources().getIntArray(indicatorColorsId);
        }
        radiusOffset = radiusMax - radiusMin;
    }

    public void setViewPager(com.ryanharter.viewpager.ViewPager mViewPager) {
        this.viewPager = mViewPager;
        initSpringView();
    }

    private void initSpringView() {
        addPointView();
        addTabContainerView();
        addTabItems();
    }

    private void addPointView() {
        springView = new SpringView(getContext());
        springView.setIndicatorColor(getResources().getColor(indicatorColorId));
        addView(springView);
    }

    private void addTabContainerView() {
        tabContainer = new LinearLayout(getContext());
        tabContainer.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT, 1.0f));
        tabContainer.setOrientation(LinearLayout.HORIZONTAL);
        tabContainer.setGravity(Gravity.CENTER);
        addView(tabContainer);
    }

    private void addTabItems() {
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT, 1.0f);
        tabs = new ArrayList<TextView>();
        for (int i = 0; i < viewPager.getAdapter().getCount(); i++) {
            TextView textView = new TextView(getContext());
            if (viewPager.getAdapter().getPageTitle(i) != null) {
                textView.setText(viewPager.getAdapter().getPageTitle(i));
            }
            textView.setGravity(Gravity.CENTER);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
            textView.setTextColor(getResources().getColor(textColorId));
            if (textBgResId != 0) {
                textView.setBackgroundResource(textBgResId);
            }
            textView.setLayoutParams(layoutParams);
            final int position = i;
            textView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (tabClickListener == null || tabClickListener.onTabClick(position)) {
                        viewPager.setCurrentItem(position);
                    }
                }
            });
            tabs.add(textView);
            tabContainer.addView(textView);
        }
    }

    /**
     * Set current point position.
     */
    private void createPoints() {
        View view = tabs.get(viewPager.getCurrentItem());
        springView.getHeadPoint().setX(view.getX() + view.getWidth() / 2);
        springView.getHeadPoint().setY(view.getY() + view.getHeight() / 2);
        springView.getFootPoint().setX(view.getX() + view.getWidth() / 2);
        springView.getFootPoint().setY(view.getY() + view.getHeight() / 2);
        springView.animCreate();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        createPoints();
        setSelectedTextColor(viewPager.getCurrentItem());
    }

    public void onPageSelected(int position) {
        setSelectedTextColor(position);
        if (delegateListener != null) {
            delegateListener.onPageSelected(position);
        }
    }

    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (position < tabs.size() - 1) {
            // radius
            float radiusOffsetHead = 0.5f;
            if (positionOffset < radiusOffsetHead) {
                springView.getHeadPoint().setRadius(radiusMin);
            } else {
                springView.getHeadPoint().setRadius(
                        ((positionOffset - radiusOffsetHead) / (1 - radiusOffsetHead) * radiusOffset + radiusMin));
            }
            float radiusOffsetFoot = 0.5f;
            if (positionOffset < radiusOffsetFoot) {
                springView.getFootPoint()
                        .setRadius((1 - positionOffset / radiusOffsetFoot) * radiusOffset + radiusMin);
            } else {
                springView.getFootPoint().setRadius(radiusMin);
            }

            // x
            float headX = 1f;
            if (positionOffset < headMoveOffset) {
                float positionOffsetTemp = positionOffset / headMoveOffset;
                headX = (float) ((Math.atan(positionOffsetTemp * acceleration * 2 - acceleration)
                        + (Math.atan(acceleration))) / (2 * (Math.atan(acceleration))));
            }
            springView.getHeadPoint().setX(getTabX(position) - headX * getPositionDistance(position));
            float footX = 0f;
            if (positionOffset > footMoveOffset) {
                float positionOffsetTemp = (positionOffset - footMoveOffset) / (1 - footMoveOffset);
                footX = (float) ((Math.atan(positionOffsetTemp * acceleration * 2 - acceleration)
                        + (Math.atan(acceleration))) / (2 * (Math.atan(acceleration))));
            }
            springView.getFootPoint().setX(getTabX(position) - footX * getPositionDistance(position));

            // reset radius
            if (positionOffset == 0) {
                springView.getHeadPoint().setRadius(radiusMax);
                springView.getFootPoint().setRadius(radiusMax);
            }
        } else {
            springView.getHeadPoint().setX(getTabX(position));
            springView.getFootPoint().setX(getTabX(position));
            springView.getHeadPoint().setRadius(radiusMax);
            springView.getFootPoint().setRadius(radiusMax);
        }

        // set indicator colors
        // https://github.com/TaurusXi/GuideBackgroundColorAnimation
        if (indicatorColorsId != 0) {
            float length = (position + positionOffset) / viewPager.getAdapter().getCount();
            int progress = (int) (length * INDICATOR_ANIM_DURATION);
            seek(progress);
        }

        springView.postInvalidate();
        if (delegateListener != null) {
            delegateListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
        }
    }

    public void onPageScrollStateChanged(int state) {
        if (delegateListener != null) {
            delegateListener.onPageScrollStateChanged(state);
        }
    }

    private float getPositionDistance(int position) {
        float tarX = tabs.get(position + 1).getX();
        float oriX = tabs.get(position).getX();
        return oriX - tarX;
    }

    private float getTabX(int position) {
        return tabs.get(position).getX() + tabs.get(position).getWidth() / 2;
    }

    private void setSelectedTextColor(int position) {
        for (TextView tab : tabs) {
            tab.setTextColor(textColorId);
        }
        tabs.get(position).setTextColor(getResources().getColor(selectedTextColorId));
    }

    private void createIndicatorColorAnim() {
        indicatorColorAnim = ObjectAnimator.ofInt(springView, "indicatorColor", indicatorColorArray);
        indicatorColorAnim.setEvaluator(new ArgbEvaluator());
        indicatorColorAnim.setDuration(INDICATOR_ANIM_DURATION);
    }

    private void seek(long seekTime) {
        if (indicatorColorAnim == null) {
            createIndicatorColorAnim();
        }
        indicatorColorAnim.setCurrentPlayTime(seekTime);
    }

    public List<TextView> getTabs() {
        return tabs;
    }

    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
        this.delegateListener = listener;
    }

    public void setOnTabClickListener(TabClickListener listener) {
        this.tabClickListener = listener;
    }
}