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
阅读全文
0 0
- Android底部bottom的渐变实现
- Android炫酷的Toolbar+Bottom+Fab悬浮按钮显示、隐藏、渐变的各种实现姿势
- 使用Bottom Navigation Activity实现Android底部导航栏
- Android实现背景透明度渐变的效果,类似于分享底部的弹出框
- Bottom Sheets实现底部动作条
- 使用Bottom Sheet实现底部菜单
- Android 仿微信底部渐变Tab
- 微信底部滑动时图标渐变色的实现
- 如何制作网页的底部/bottom
- 底部导航Bottom navigation的简单使用
- 如何滚动到UITabelView的底部(bottom)
- bottom 属性规定元素的底部边缘
- Android渐变标题栏的实现
- android渐变Toolbar的实现
- 关于Linearlayout中控件设置为其底部的问题,android:layout_gravity="bottom"没效果
- Android底部菜单的实现
- 使用Bottom Sheet实现底部菜单,初步识别
- android高仿微信底部渐变导航栏
- hashcode理解
- iOS开发关于oc运行时 isa指针详解
- Swift--01数据声明
- Foundations of Machine Learning 内容整理 —— Introduction
- 水流波动效果的进度条
- Android底部bottom的渐变实现
- Android背景渐变色(shape,gradient)
- python面试相关
- tomcat的热部署和热加载(无需重启tomcat自动重新生成class文件)
- Linux下,Tomcat8修改jvm内存配置
- Easy-49
- python 导入模块和解决文件句柄找不到问题
- 深入浅出MySQL
- JAVA_OPTS设置