Android底部bottom的渐变实现

来源:互联网 发布:淘宝灵符小镇岑一道长 编辑:程序博客网 时间:2024/05/16 20:07

工程代码大致结构
工程代码大致结构
与tab有关的代码

package com.sage.cmp.ui.exercise_project.view;import android.content.Context;import android.os.Bundle;import android.os.Parcelable;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.View;import android.widget.LinearLayout;import java.util.ArrayList;import java.util.List;/** *  AlphaTabsIndicator类 */public class AlphaTabsIndicator extends LinearLayout {    private ViewPager mViewPager;    private OnTabChangedListner mListner;    private List<AlphaTabView> mTabViews;    private boolean ISINIT;    /**     * 子View的数量     */    private int mChildCounts;    /**     * 当前的条目索引     */    private int mCurrentItem = 0;    public AlphaTabsIndicator(Context context) {        this(context, null);    }    public AlphaTabsIndicator(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public AlphaTabsIndicator(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        post(new Runnable() {            @Override            public void run() {                isInit();            }        });    }    public void setViewPager(ViewPager mViewPager) {        this.mViewPager = mViewPager;        init();    }    public void setOnTabChangedListner(OnTabChangedListner listner) {        this.mListner = listner;        isInit();    }    public AlphaTabView getCurrentItemView() {        isInit();        return mTabViews.get(mCurrentItem);    }    public AlphaTabView getTabView(int tabIndex) {        isInit();        return mTabViews.get(tabIndex);    }    public void removeAllBadge() {        isInit();        for (AlphaTabView alphaTabView : mTabViews) {            alphaTabView.removeShow();        }    }    public void setTabCurrenItem(int tabIndex) {        if (tabIndex < mChildCounts && tabIndex > -1) {            mTabViews.get(tabIndex).performClick();        } else {            throw new IllegalArgumentException("IndexOutOfBoundsException");        }    }    private void isInit() {        if (!ISINIT) {            init();        }    }    private void init() {        ISINIT = true;        mTabViews = new ArrayList<>();        mChildCounts = getChildCount();        if (null != mViewPager) {            if (null == mViewPager.getAdapter()) {                throw new NullPointerException("viewpager的adapter为null");            }            if (mViewPager.getAdapter().getCount() != mChildCounts) {                throw new IllegalArgumentException("子View数量必须和ViewPager条目数量一致");            }            //对ViewPager添加监听            mViewPager.addOnPageChangeListener(new MyOnPageChangeListener());        }        for (int i = 0; i < mChildCounts; i++) {            if (getChildAt(i) instanceof AlphaTabView) {                AlphaTabView tabView = (AlphaTabView) getChildAt(i);                mTabViews.add(tabView);                //设置点击监听                tabView.setOnClickListener(new MyOnClickListener(i));            } else {                throw new IllegalArgumentException("TabIndicator的子View必须是TabView");            }        }        mTabViews.get(mCurrentItem).setIconAlpha(1.0f);    }    private class MyOnPageChangeListener extends ViewPager.SimpleOnPageChangeListener {        @Override        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            //滑动时的透明度动画            if (positionOffset > 0) {                mTabViews.get(position).setIconAlpha(1 - positionOffset);                mTabViews.get(position + 1).setIconAlpha(positionOffset);            }            //滑动时保存当前按钮索引            mCurrentItem = position;        }        @Override        public void onPageSelected(int position) {            super.onPageSelected(position);            resetState();            mTabViews.get(position).setIconAlpha(1.0f);            mCurrentItem = position;        }    }    private class MyOnClickListener implements OnClickListener {        private int currentIndex;        public MyOnClickListener(int i) {            this.currentIndex = i;        }        @Override        public void onClick(View v) {            //点击前先重置所有按钮的状态            resetState();            mTabViews.get(currentIndex).setIconAlpha(1.0f);            if (null != mListner) {                mListner.onTabSelected(currentIndex);            }            if (null != mViewPager) {                //不能使用平滑滚动,否者颜色改变会乱                mViewPager.setCurrentItem(currentIndex, false);            }            //点击是保存当前按钮索引            mCurrentItem = currentIndex;        }    }    /**     * 重置所有按钮的状态     */    private void resetState() {        for (int i = 0; i < mChildCounts; i++) {            mTabViews.get(i).setIconAlpha(0);        }    }    private static final String STATE_INSTANCE = "instance_state";    private static final String STATE_ITEM = "state_item";    /**     * @return 当View被销毁的时候,保存数据     */    @Override    protected Parcelable onSaveInstanceState() {        Bundle bundle = new Bundle();        bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());        bundle.putInt(STATE_ITEM, mCurrentItem);        return bundle;    }    /**     * @param state 用于恢复数据使用     */    @Override    protected void onRestoreInstanceState(Parcelable state) {        if (state instanceof Bundle) {            Bundle bundle = (Bundle) state;            mCurrentItem = bundle.getInt(STATE_ITEM);            if (null == mTabViews || mTabViews.isEmpty()) {                super.onRestoreInstanceState(state);                return;            }            //重置所有按钮状态            resetState();            //恢复点击的条目颜色            mTabViews.get(mCurrentItem).setIconAlpha(1.0f);            super.onRestoreInstanceState(bundle.getParcelable(STATE_INSTANCE));        } else {            super.onRestoreInstanceState(state);        }    }}
package com.sage.cmp.ui.exercise_project.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.Typeface;import android.graphics.drawable.BitmapDrawable;import android.os.Looper;import android.util.AttributeSet;import android.util.TypedValue;import android.view.View;import com.sage.cmp.ui.exercise_project.R;/** *  AlphaTabView 类 *  可以渐变的View */public class AlphaTabView extends View {    private Context mContext;                     //上下文    private Bitmap mIconNormal;                   //默认图标    private Bitmap mIconSelected;                 //选中的图标    private String mText;                         //描述文本    private int mTextColorNormal = 0xFF999999;    //描述文本的默认显示颜色    private int mTextColorSelected = 0xFF46C01B;  //述文本的默认选中显示颜色    private int mTextSize = 12;                   //描述文本的默认字体大小 12sp    private int mPadding = 5;                      //文字和图片之间的距离 5dp    private float mAlpha;                         //当前的透明度    private Paint mSelectedPaint = new Paint();   //背景的画笔    private Rect mIconAvailableRect = new Rect(); //图标可用的绘制区域    private Rect mIconDrawRect = new Rect();      //图标真正的绘制区域    private Paint mTextPaint;                     //描述文本的画笔    private Rect mTextBound;                      //描述文本矩形测量大小    private Paint.FontMetricsInt mFmi;            //用于获取字体的各种属性    private boolean isShowRemove;                //是否移除当前角标    private boolean isShowPoint;                //是否显示圆点    private int mBadgeNumber;                       //角标数    private int mBadgeBackgroundColor = 0xFFFF0000;       //默认红颜色    public AlphaTabView(Context context) {        this(context, null);        mContext = context;    }    public AlphaTabView(Context context, AttributeSet attrs) {        this(context, attrs, 0);        mContext = context;    }    public AlphaTabView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;        mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize, getResources().getDisplayMetrics());        mPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPadding, getResources().getDisplayMetrics());        //获取所有的自定义属性        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AlphaTabView);        BitmapDrawable iconNormal = (BitmapDrawable) a.getDrawable(R.styleable.AlphaTabView_tabIconNormal);        if (iconNormal != null) {            mIconNormal = iconNormal.getBitmap();        }        BitmapDrawable iconSelected = (BitmapDrawable) a.getDrawable(R.styleable.AlphaTabView_tabIconSelected);        if (iconSelected != null) {            mIconSelected = iconSelected.getBitmap();        }        if (null != mIconNormal) {            mIconSelected = null == mIconSelected ? mIconNormal : mIconSelected;        } else {            mIconNormal = null == mIconSelected ? mIconNormal : mIconSelected;        }        mText = a.getString(R.styleable.AlphaTabView_tabText);        mTextSize = a.getDimensionPixelSize(R.styleable.AlphaTabView_tabTextSize, mTextSize);        mTextColorNormal = a.getColor(R.styleable.AlphaTabView_textColorNormal, mTextColorNormal);        mTextColorSelected = a.getColor(R.styleable.AlphaTabView_textColorSelected, mTextColorSelected);        mBadgeBackgroundColor = a.getColor(R.styleable.AlphaTabView_badgeBackgroundColor, mBadgeBackgroundColor);        mPadding = (int) a.getDimension(R.styleable.AlphaTabView_paddingTexwithIcon, mPadding);        a.recycle();        initText();    }    /**     * 如果有设置文字就获取文字的区域大小     */    private void initText() {        if (mText != null) {            mTextBound = new Rect();            mTextPaint = new Paint();            mTextPaint.setTextSize(mTextSize);            mTextPaint.setAntiAlias(true);            mTextPaint.setDither(true);            mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);            mFmi = mTextPaint.getFontMetricsInt();        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        if (mText == null && (mIconNormal == null || mIconSelected == null)) {            throw new IllegalArgumentException("必须设置 tabText 或者 tabIconSelected、tabIconNormal 两个,或者全部设置");        }        int paddingLeft = getPaddingLeft();        int paddingTop = getPaddingTop();        int paddingRight = getPaddingRight();        int paddingBottom = getPaddingBottom();        int measuredWidth = getMeasuredWidth();        int measuredHeight = getMeasuredHeight();        //计算出可用绘图的区域        int availableWidth = measuredWidth - paddingLeft - paddingRight;        int availableHeight = measuredHeight - paddingTop - paddingBottom;        if (mText != null && mIconNormal != null) {            availableHeight -= (mTextBound.height() + mPadding);            //计算出图标可以绘制的画布大小            mIconAvailableRect.set(paddingLeft, paddingTop, paddingLeft + availableWidth, paddingTop + availableHeight);            //计算文字的绘图区域            int textLeft = paddingLeft + (availableWidth - mTextBound.width()) / 2;            int textTop = mIconAvailableRect.bottom + mPadding;            mTextBound.set(textLeft, textTop, textLeft + mTextBound.width(), textTop + mTextBound.height());        } else if (mText == null) {            //计算出图标可以绘制的画布大小            mIconAvailableRect.set(paddingLeft, paddingTop, paddingLeft + availableWidth, paddingTop + availableHeight);        } else if (mIconNormal == null) {            //计算文字的绘图区域            int textLeft = paddingLeft + (availableWidth - mTextBound.width()) / 2;            int textTop = paddingTop + (availableHeight - mTextBound.height()) / 2;            mTextBound.set(textLeft, textTop, textLeft + mTextBound.width(), textTop + mTextBound.height());        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        int alpha = (int) Math.ceil(mAlpha * 255);        if (mIconNormal != null && mIconSelected != null) {            Rect drawRect = availableToDrawRect(mIconAvailableRect, mIconNormal);            mSelectedPaint.reset();            mSelectedPaint.setAntiAlias(true);//设置抗锯齿            mSelectedPaint.setFilterBitmap(true);//抗锯齿            mSelectedPaint.setAlpha(255 - alpha);            canvas.drawBitmap(mIconNormal, null, drawRect, mSelectedPaint);            mSelectedPaint.reset();            mSelectedPaint.setAntiAlias(true);//设置抗锯齿            mSelectedPaint.setFilterBitmap(true);//抗锯齿            mSelectedPaint.setAlpha(alpha); //setAlpha必须放在paint的属性最后设置,否则不起作用            canvas.drawBitmap(mIconSelected, null, drawRect, mSelectedPaint);        }        if (mText != null) {            //绘制原始文字,setAlpha必须放在paint的属性最后设置,否则不起作用            mTextPaint.setColor(mTextColorNormal);            mTextPaint.setAlpha(255 - alpha);            //由于在该方法中,y轴坐标代表的是baseLine的值,经测试,mTextBound.height() + mFmi.bottom 就是字体的高            //所以在最后绘制前,修正偏移量,将文字向上修正 mFmi.bottom / 2 即可实现垂直居中            canvas.drawText(mText, mTextBound.left, mTextBound.bottom - mFmi.bottom / 2, mTextPaint);            //绘制变色文字,setAlpha必须放在paint的属性最后设置,否则不起作用            mTextPaint.setColor(mTextColorSelected);            mTextPaint.setAlpha(alpha);            canvas.drawText(mText, mTextBound.left, mTextBound.bottom - mFmi.bottom / 2, mTextPaint);        }        //绘制角标        if (!isShowRemove) {            drawBadge(canvas);        }    }    /**     * badge     */    private void drawBadge(Canvas canvas) {        int i = getMeasuredWidth() / 14;        int j = getMeasuredHeight() / 9;        i = i >= j ? j : i;        if (mBadgeNumber > 0) {            Paint backgroundPaint = new Paint();            backgroundPaint.setColor(mBadgeBackgroundColor);            backgroundPaint.setAntiAlias(true);            String number = mBadgeNumber > 99 ? "99+" : String.valueOf(mBadgeNumber);            float textSize = i / 1.5f == 0 ? 5 : i / 1.5f;            int width;            int hight = (int) dp2px(mContext, i);            Bitmap bitmap;            if (number.length() == 1) {                width = (int) dp2px(mContext, i);                bitmap = Bitmap.createBitmap(width, hight, Bitmap.Config.ARGB_8888);            } else if (number.length() == 2) {                width = (int) dp2px(mContext, i + 5);                bitmap = Bitmap.createBitmap(width, hight, Bitmap.Config.ARGB_8888);            } else {                width = (int) dp2px(mContext, i + 8);                bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);            }            Canvas canvasMessages = new Canvas(bitmap);            RectF messageRectF = new RectF(0, 0, width, hight);            canvasMessages.drawRoundRect(messageRectF, 50, 50, backgroundPaint); //画椭圆            Paint numberPaint = new Paint();            numberPaint.setColor(Color.WHITE);            numberPaint.setTextSize(dp2px(mContext, textSize));            numberPaint.setAntiAlias(true);            numberPaint.setTextAlign(Paint.Align.CENTER);            numberPaint.setTypeface(Typeface.DEFAULT_BOLD);            Paint.FontMetrics fontMetrics = numberPaint.getFontMetrics();            float x = width / 2f;            float y = hight / 2f - fontMetrics.descent + (fontMetrics.descent - fontMetrics.ascent) / 2;            canvasMessages.drawText(number, x, y, numberPaint);            float left = getMeasuredWidth() / 10 * 6f;            float top = dp2px(mContext, 5);            canvas.drawBitmap(bitmap, left, top, null);            bitmap.recycle();        } else if (mBadgeNumber == 0) {        } else {            if (isShowPoint) {                Paint paint = new Paint();                paint.setColor(mBadgeBackgroundColor);                paint.setAntiAlias(true);                float left = getMeasuredWidth() / 10 * 6f;                float top = dp2px(getContext(), 5);                i = i > 10 ? 10 : i;                float width = dp2px(getContext(), i);                RectF messageRectF = new RectF(left, top, left + width, top + width);                canvas.drawOval(messageRectF, paint);            }        }    }    public void showPoint() {        isShowRemove = false;        mBadgeNumber = -1;        isShowPoint = true;        invalidate();    }    public void showNumber(int badgeNum) {        isShowRemove = false;        isShowPoint = false;        mBadgeNumber = badgeNum;        if (badgeNum > 0) {            invalidate();        } else {            isShowRemove = true;            invalidate();        }    }    public void removeShow() {        mBadgeNumber = 0;        isShowPoint = false;        isShowRemove = true;        invalidate();    }    public int getBadgeNumber() {        return mBadgeNumber;    }    public boolean isShowPoint() {        return isShowPoint;    }    private Rect availableToDrawRect(Rect availableRect, Bitmap bitmap) {        float dx = 0, dy = 0;        float wRatio = availableRect.width() * 1.0f / bitmap.getWidth();        float hRatio = availableRect.height() * 1.0f / bitmap.getHeight();        if (wRatio > hRatio) {            dx = (availableRect.width() - hRatio * bitmap.getWidth()) / 2;        } else {            dy = (availableRect.height() - wRatio * bitmap.getHeight()) / 2;        }        int left = (int) (availableRect.left + dx + 0.5f);        int top = (int) (availableRect.top + dy + 0.5f);        int right = (int) (availableRect.right - dx + 0.5f);        int bottom = (int) (availableRect.bottom - dy + 0.5f);        mIconDrawRect.set(left, top, right, bottom);        return mIconDrawRect;    }    /**     * @param alpha 对外提供的设置透明度的方法,取值 0.0 ~ 1.0     */    public void setIconAlpha(float alpha) {        if (alpha < 0 || alpha > 1) {            throw new IllegalArgumentException("透明度必须是 0.0 - 1.0");        }        mAlpha = alpha;        invalidateView();    }    /**     * 根据当前所在线程更新界面     */    private void invalidateView() {        if (Looper.getMainLooper() == Looper.myLooper()) {            invalidate();        } else {            postInvalidate();        }    }    private float dp2px(Context context, float dipValue) {        float scale = context.getResources().getDisplayMetrics().density;        return (int) (dipValue * scale);    }}
/** * tab监听回调 */public interface OnTabChangedListner {    void onTabSelected(int tabNum);}
/***  values文件下的attrs.xml*/<?xml version="1.0" encoding="utf-8"?><resources>    <!--透明渐变的TabView-->    <declare-styleable name="AlphaTabView">        <attr name="tabIconNormal" format="reference" />        <attr name="tabIconSelected" format="reference" />        <attr name="tabText" format="string" />        <attr name="tabTextSize" format="dimension" />        <attr name="textColorNormal" format="color" />        <attr name="textColorSelected" format="color" />        <attr name="badgeBackgroundColor" format="color" />        <attr name="paddingTexwithIcon" format="dimension"/>    </declare-styleable></resources>

UI界面的实现过程

/***  activity_tab_alpha.xml*/<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <android.support.v4.view.ViewPager        android:id="@+id/vp"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"/>    <View        android:layout_width="match_parent"        android:layout_height="0.5dp"        android:background="#888"/>    <com.sage.cmp.ui.exercise_project.view.AlphaTabsIndicator        android:id="@+id/tabs_indicator"        android:layout_width="match_parent"        android:layout_height="55dp"        android:orientation="horizontal"        android:padding="5dp">        <com.sage.cmp.ui.exercise_project.view.AlphaTabView            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            app:paddingTexwithIcon="4dp"            app:tabIconNormal="@mipmap/home_normal"            app:tabIconSelected="@mipmap/home_selected"            app:tabText="微信"            app:tabTextSize="13sp"            app:textColorNormal="#999999"            app:textColorSelected="#46c01b"/>        <com.sage.cmp.ui.exercise_project.view.AlphaTabView            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            app:paddingTexwithIcon="4dp"            app:tabIconNormal="@mipmap/category_normal"            app:tabIconSelected="@mipmap/category_selected"            app:tabText="通讯录"            app:tabTextSize="13sp"            app:textColorNormal="#999999"            app:textColorSelected="#46c01b"/>        <com.sage.cmp.ui.exercise_project.view.AlphaTabView            android:id="@+id/alphaTabView"            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            app:paddingTexwithIcon="4dp"            app:tabIconNormal="@mipmap/service_normal"            app:tabIconSelected="@mipmap/service_selected"            app:tabText="发现"            app:tabTextSize="13sp"            app:textColorNormal="#999999"            app:textColorSelected="#46c01b"/>        <com.sage.cmp.ui.exercise_project.view.AlphaTabView            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            app:paddingTexwithIcon="4dp"            app:tabIconNormal="@mipmap/mine_normal"            app:tabIconSelected="@mipmap/mine_selected"            app:tabText="我的"            app:tabTextSize="13sp"            app:textColorNormal="#999999"            app:textColorSelected="#46c01b"/>    </com.sage.cmp.ui.exercise_project.view.AlphaTabsIndicator></LinearLayout>
package com.sage.cmp.ui.exercise_project;import android.support.v4.view.ViewPager;import com.sage.cmp.ui.exercise_project.ui.adapter.TabFragmentPagerAdapter;import com.sage.cmp.ui.exercise_project.view.AlphaTabsIndicator;/** * AlphaTabActivity 类  * 是实现底部渐变效果的 */public class AlphaTabActivity extends BaseActivity {    private ViewPager mVP;    private AlphaTabsIndicator mTabsIndicator;    private TabFragmentPagerAdapter adapter;    @Override    protected int rootLayoutId() {        return R.layout.activity_tab_alpha;    }    @Override    protected void initOnCreate() {        initView();        setAdapter();    }    private void setAdapter() {        adapter=new TabFragmentPagerAdapter(getSupportFragmentManager(),this);        mVP.setAdapter(adapter);        mTabsIndicator.setViewPager(mVP);    }    private void initView() {        mVP = (ViewPager) findViewById(R.id.vp);        mTabsIndicator = (AlphaTabsIndicator) findViewById(R.id.tabs_indicator);    }}
package com.sage.cmp.ui.exercise_project.ui.adapter;import android.content.Context;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentPagerAdapter;import com.sage.cmp.ui.exercise_project.R;import com.sage.cmp.ui.exercise_project.ui.fragment.CreateFragmentFactory;/** * FragmentPagerAdapter适配器, */public class TabFragmentPagerAdapter extends FragmentPagerAdapter {    private String[] tabsTitle;    public TabFragmentPagerAdapter(FragmentManager fm, Context context) {        super(fm);        tabsTitle = context.getResources().getStringArray(R.array.tab_bottom_info);    }    @Override    public Fragment getItem(int position) {        return CreateFragmentFactory.createBaseFragmentFactory(position);    }    @Override    public int getCount() {        return tabsTitle.length;    }}

参考gitHub网址:https://github.com/yingLanNull/AlphaTabsIndicator

原创粉丝点击