【Android - 自定义View】之自定义颜色渐变的Tab导航栏
首先来介绍一下这个自定义View:
- (1)这个自定义View的名称叫做 GradientTab ,继承自View类;
- (2)这个自定义View实现了颜色渐变的Tab导航栏(仿微信主菜单),用户在左右滑动的时候,当前页对应的Tab逐渐变淡,目标页的Tab逐渐变深;
- (3)用户可以在XML布局中自定义变色的颜色、图标、文本、文本大小、文本颜色、图文间隔等属性。
接下来简单介绍一下在这个自定义View中用到的技术点:
- (1)自定义属性;
- (2)在 onMeasure() 方法中对View进行测量;
- (3)在 onLayout() 方法中进行一些在获取到测量值之后才能进行的操作,避免代码多次调用影响性能;
- (4)使用 Canvas 、 Paint 、 Bitmap 类对自定义View进行绘制;
- (5)通过 onSaveInstanceState() 和 onRestoreInstanceState() 方法保存和重置View状态(透明度)。
下面是这个自定义View—— GradientTab 的实现代码:
自定义View类 GradientTab.java 中的代码:
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; /** * 与ViewPager连用的拖动可渐变色的Tab按钮 */ public class GradientTab extends View { private int width, height; // View最终显示的宽高 private int backColor = Color.GREEN; // 自定义属性:Tab按钮的背景颜色 private int spacing = -1; // 自定义属性:Tab按钮中图标和文本的间隔 private StringBuffer text = new StringBuffer(); // 自定义属性:Tab按钮中显示的文本 private int textColor = Color.BLACK; // 自定义属性:Tab按钮中文本的颜色 private int textSize = -1; // 自定义属性:Tab按钮的文本大小 private Bitmap tabBitmap; // 绘制元素的Bitmap private Bitmap tmpBm; // 临时Bitmap private Paint tabPaint; // 绘制元素的画笔 private Paint iconPaint; // 绘制图标的画笔 private Paint textPaint; // 绘制文本的画笔 private Bitmap iconBm; // 图标图片对应的Bitmap private float iconWidth; // 图标图片的宽度 private float iconHeight; // 图标图片的高度 private int alpha = 0; // 透明度 public GradientTab(Context context) { this(context, null); } public GradientTab(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public GradientTab(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 加载自定义属性 TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GradientTab, defStyleAttr, 0); int count = array.getIndexCount(); for (int i = 0; i < count; i++) { int attr = array.getIndex(i); switch (attr) { case R.styleable.GradientTab_backColor: backColor = array.getColor(attr, Color.GREEN); break; case R.styleable.GradientTab_iconImg: int iconRes = array.getResourceId(attr, -1); // 自定义属性:Tab按钮中显示的图标的资源ID if (iconRes != -1) { iconBm = BitmapFactory.decodeResource(getResources(), iconRes); iconWidth = iconBm.getWidth(); iconHeight = iconBm.getHeight(); } break; case R.styleable.GradientTab_spacing: textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics())), context.getResources().getDisplayMetrics()); break; case R.styleable.GradientTab_text: text.delete(0, text.length()); text.append(array.getString(attr)); break; case R.styleable.GradientTab_textColor: textColor = array.getColor(attr, Color.BLACK); break; case R.styleable.GradientTab_textSize: textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics())), context.getResources().getDisplayMetrics()); break; } } array.recycle(); // 为一些自定义属性设置默认值 if (textSize == -1) { textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics()); } if (spacing == -1) { spacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics()); } // 进行一些对象的初始化操作 init(); } /** * 进行一些对象的初始化操作 */ private void init() { // 初始化绘制图标的画笔 iconPaint = new Paint(); iconPaint.setAntiAlias(true); iconPaint.setDither(true); // 初始化绘制文本的画笔 textPaint = new Paint(); textPaint.setAntiAlias(true); textPaint.setDither(true); textPaint.setColor(textColor); textPaint.setTextSize(textSize); // 初始化绘制元素的画笔 tabPaint = new Paint(); tabPaint.setAntiAlias(true); tabPaint.setDither(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = getMeasuredWidth(); height = getMeasuredHeight(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // 初始化绘制元素的画布 tabBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas tabCanvas = new Canvas(tabBitmap); // 对图标进行缩放 int widthLeft = width - getPaddingLeft() - getPaddingRight(); int heightLeft = height - getPaddingTop() - getPaddingBottom() - textSize - spacing; float scale = (float) Math.min(widthLeft * 1.0 / iconWidth, heightLeft * 1.0 / iconHeight); Matrix matrix = new Matrix(); matrix.postScale(scale, scale); iconBm = Bitmap.createBitmap(iconBm, 0, 0, (int) iconWidth, (int) iconHeight, matrix, true); iconWidth *= scale; iconHeight *= scale; // 将图标和文本绘制到绘制元素的画布上 tabCanvas.drawBitmap(iconBm, (widthLeft - iconWidth) / 2, getPaddingTop(), iconPaint); int textWidth = (int) textPaint.measureText(text.toString()); tabCanvas.drawText(text.toString(), (widthLeft - textWidth) / 2, height - getPaddingBottom(), textPaint); tmpBm = tabBitmap.copy(Bitmap.Config.ARGB_8888, false); tabPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); tabPaint.setColor(backColor); tabCanvas.drawRect(0, 0, width, height, tabPaint); } @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(tmpBm, 0, 0, null); // 绘制图标和文本 Paint paint = new Paint(); paint.setAlpha(alpha); canvas.drawBitmap(tabBitmap, 0, 0, paint); } public void setAlpha(float alpha) { this.alpha = (int) Math.ceil(255 * alpha); invalidate(); } /** * 当这个View所在的Activity临时结束时,保存当前状态(透明度) */ @Override protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable("default", super.onSaveInstanceState()); bundle.putInt("alpha", alpha); return bundle; } /** * 当这个View所在的Activity重新打开时,重置当前状态(透明度) */ @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; alpha = bundle.getInt("alpha"); super.onRestoreInstanceState(bundle.getParcelable("default")); } super.onRestoreInstanceState(state); } }
自定义属性文件 attr.xml 中的代码:
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="backColor" format="color" /> <attr name="iconImg" format="reference" /> <attr name="spacing" format="dimension" /> <attr name="text" format="string" /> <attr name="textColor" format="color" /> <attr name="textSize" format="dimension" /> <declare-styleable name="GradientTab"> <attr name="backColor" /> <attr name="iconImg" /> <attr name="spacing" /> <attr name="text" /> <attr name="textColor" /> <attr name="textSize" /> </declare-styleable> </resources>
主界面布局 activity_main.xml 文件中的代码:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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"> <LinearLayout android:id="@+id/gradienttab_main_ly_tabs" android:layout_width="match_parent" android:layout_height="60.0dip" android:layout_alignParentBottom="true" android:background="#EEEEEE" android:orientation="horizontal"> <my.itgungnir.custom_gradientmenu.GradientTab android:id="@+id/gradienttab_main_tab_tab1" android:layout_width="0.0dip" android:layout_height="match_parent" android:layout_weight="1" android:padding="3.0dip" app:backColor="#008800" app:iconImg="@mipmap/menu_tab1" app:spacing="2.0dip" app:text="Tab1" app:textColor="#888888" app:textSize="8.0sp" /> <my.itgungnir.custom_gradientmenu.GradientTab android:id="@+id/gradienttab_main_tab_tab2" android:layout_width="0.0dip" android:layout_height="match_parent" android:layout_weight="1" android:padding="3.0dip" app:backColor="#880000" app:iconImg="@mipmap/menu_tab2" app:spacing="2.0dip" app:text="Tab2" app:textColor="#888888" app:textSize="8.0sp" /> <my.itgungnir.custom_gradientmenu.GradientTab android:id="@+id/gradienttab_main_tab_tab3" android:layout_width="0.0dip" android:layout_height="match_parent" android:layout_weight="1" android:padding="3.0dip" app:backColor="#000088" app:iconImg="@mipmap/menu_tab3" app:spacing="2.0dip" app:text="Tab3" app:textColor="#888888" app:textSize="8.0sp" /> <my.itgungnir.custom_gradientmenu.GradientTab android:id="@+id/gradienttab_main_tab_tab4" android:layout_width="0.0dip" android:layout_height="match_parent" android:layout_weight="1" android:padding="3.0dip" app:backColor="#888888" app:iconImg="@mipmap/menu_tab4" app:spacing="2.0dip" app:text="Tab4" app:textColor="#888888" app:textSize="8.0sp" /> </LinearLayout> <android.support.v4.view.ViewPager android:id="@+id/gradienttab_main_vp_pages" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/gradienttab_main_ly_tabs" /> </RelativeLayout>
主界面JAVA文件 MainActivity.java 中的代码:
import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import java.util.ArrayList; import java.util.List; public class MainActivity extends FragmentActivity { private ViewPager viewpager; private List<GradientTab> tabList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onResume() { super.onResume(); viewpager = (ViewPager) findViewById(R.id.gradienttab_main_vp_pages); initData(); initEvents(); } private void initData() { // 初始化盛放Fragment的列表 final List<Fragment> list = new ArrayList<>(); for (int i = 1; i <= 4; i++) { PageFragment fragment = new PageFragment(); Bundle bundle = new Bundle(); bundle.putString("title", "This is page " + i); fragment.setArguments(bundle); list.add(fragment); } // 为ViewPager适配数据 viewpager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int position) { return list.get(position); } @Override public int getCount() { return list.size(); } }); // 初始化四个Tab按钮,添加到List列表中 tabList = new ArrayList<>(); tabList.add((GradientTab) findViewById(R.id.gradienttab_main_tab_tab1)); tabList.add((GradientTab) findViewById(R.id.gradienttab_main_tab_tab2)); tabList.add((GradientTab) findViewById(R.id.gradienttab_main_tab_tab3)); tabList.add((GradientTab) findViewById(R.id.gradienttab_main_tab_tab4)); } private void initEvents() { // ViewPager的滚动事件 viewpager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { tabList.get(position).setAlpha(1 - positionOffset); tabList.get((int) Math.ceil(position + positionOffset)).setAlpha(positionOffset == 0 ? 1 : positionOffset); } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } }); } }
运行效果图如下所示:
posted on 2017-04-24 15:07 ITGungnir 阅读(1047) 评论(0) 编辑 收藏 举报