先来看一下效果图
除了第三个的发现Tab有所差别外,其他的基本还原了微信的底部Tab渐变效果
每个Tab都是一个自定义view,根据ImageVIEw的tint属性来实现颜色渐变效果,tint属性的使用可以看我的上一篇文章
我将自定义view命名为ShadeVIEw,包含四个自定义属性
意思分别为图标、背景色、底部文本、底部文本大小
<declare-styleable name="ShadeVIEw"> <attr name="icon" format="reference" /> <attr name="color" format="color" /> <attr name="text" format="string" /> <attr name="text_size" format="dimension" /> </declare-styleable>
ShadeVIEw的定义如下,主要是进行绘图 *** 作,并向外提供改变透明度和图标的方法
public class ShadeVIEw extends VIEw { /** * 图标 */ private Bitmap iconBitmap; /** * 图标背景色 */ private int iconBackgroundcolor; /** * 图标默认背景色 */ private final int DEFAulT_ICON_BACKGROUND_color = 0x3CAF36; /** * 图标底部文本 */ private String text; /** * 图标底部文字默认大小(sp) */ private final int DEFAulT_TEXT_SIZE = 12; /** * 图标底部文字默认颜色 */ private final int DEFAulT_TEXT_color = 0x2B2B2B; /** * 图标绘制范围 */ private Rect iconRect; /** * 文字笔画 */ private Paint textPaint; /** * 文字范围 */ private Rect textBound; /** * 透明度(0.0-1.0) */ private float mAlpha; private Bitmap mBitmap; public ShadeVIEw(Context context,AttributeSet attrs) { super(context,attrs); //获取自定义属性值 TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.ShadeVIEw); BitmapDrawable drawable = (BitmapDrawable) typedArray.getDrawable(R.styleable.ShadeVIEw_icon); if (drawable != null) { iconBitmap = drawable.getBitmap(); } iconBackgroundcolor = typedArray.getcolor(R.styleable.ShadeVIEw_color,DEFAulT_ICON_BACKGROUND_color); text = typedArray.getString(R.styleable.ShadeVIEw_text); int textSize = (int) typedArray.getDimension(R.styleable.ShadeVIEw_text_size,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,DEFAulT_TEXT_SIZE,getResources().getdisplayMetrics())); //资源回收 typedArray.recycle(); //初始化 textBound = new Rect(); textPaint = new Paint(); textPaint.setTextSize(textSize); textPaint.setcolor(DEFAulT_TEXT_color); textPaint.setAntiAlias(true); textPaint.setDither(true); textPaint.getTextBounds(text,text.length(),textBound); } @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) { super.onMeasure(wIDthMeasureSpec,heightmeasureSpec); //因为图标是正方形且需要居中显示的,所以VIEw的大小去掉padding和文字所占空间后, //剩余的空间的宽和高的最小值才是图标的边长 int bitmapSIDe = Math.min(getMeasureDWIDth() - getpaddingleft() - getpaddingRight(),getMeasuredHeight() - getpaddingtop() - getpaddingBottom() - textBound.height()); int left = getMeasureDWIDth() / 2 - bitmapSIDe / 2; int top = (getMeasuredHeight() - textBound.height()) / 2 - bitmapSIDe / 2; //获取图标的绘制范围 iconRect = new Rect(left,top,left + bitmapSIDe,top + bitmapSIDe); } @OverrIDe protected voID onDraw(Canvas canvas) { //进一取整 int Alpha = (int) Math.ceil((255 * mAlpha)); //绘制原图标 canvas.drawBitmap(iconBitmap,null,iconRect,null); setupTargetBitmap(Alpha); drawSourceText(canvas,Alpha); drawTargetText(canvas,Alpha); canvas.drawBitmap(mBitmap,null); } /** * 在mBitmap上绘制以iconBackgroundcolor颜色为Dst,DST_IN模式下的图标 * * @param Alpha Src颜色的透明度 */ private voID setupTargetBitmap(int Alpha) { mBitmap = Bitmap.createBitmap(getMeasureDWIDth(),getMeasuredHeight(),Config.ARGB_8888); Canvas canvas = new Canvas(mBitmap); Paint paint = new Paint(); paint.setcolor(iconBackgroundcolor); paint.setAntiAlias(true); paint.setDither(true); paint.setAlpha(Alpha); //在图标背后先绘制一层iconBackgroundcolor颜色的背景 canvas.drawRect(iconRect,paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); paint.setAlpha(255); //在mBitmap上绘制以iconBackgroundcolor颜色为Dst,DST_IN模式下的图标 canvas.drawBitmap(iconBitmap,paint); } /** * 绘制默认状态下的字体 * * @param canvas Canvas * @param Alpha 字体颜色透明度 */ private voID drawSourceText(Canvas canvas,int Alpha) { textPaint.setcolor(DEFAulT_TEXT_color); textPaint.setAlpha(255 - Alpha); canvas.drawText(text,iconRect.left + iconRect.wIDth() / 2 - textBound.wIDth() / 2,iconRect.bottom + textBound.height(),textPaint); } /** * 绘制滑动到该标签时的字体 * * @param canvas Canvas * @param Alpha 字体颜色透明度 */ private voID drawTargetText(Canvas canvas,int Alpha) { textPaint.setcolor(iconBackgroundcolor); textPaint.setAlpha(Alpha); canvas.drawText(text,textPaint); } /** * 设置图标透明度并重绘 * * @param Alpha 透明度 */ public voID setIconAlpha(float Alpha) { if (mAlpha != Alpha) { this.mAlpha = Alpha; invalIDateVIEw(); } } public voID setIconBitmap(Context context,int resourceID) { BitmapDrawable bitmapDrawable = (BitmapDrawable) ContextCompat.getDrawable(context,resourceID); if (!bitmapDrawable.getBitmap().equals(iconBitmap)) { iconBitmap = bitmapDrawable.getBitmap(); invalIDateVIEw(); } } /** * 判断当前是否为UI线程,是则直接重绘,否则调用postInvalIDate()利用Handler来重绘 */ private voID invalIDateVIEw() { if (Looper.getMainLooper() == Looper.myLooper()) { invalIDate(); } else { postInvalIDate(); } } private static final String STATE_INSTANCE = "STATE_INSTANCE"; private static final String STATE_Alpha = "STATE_Alpha"; /** * 保存状态 * * @return Parcelable */ @OverrIDe protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable(STATE_INSTANCE,super.onSaveInstanceState()); bundle.putfloat(STATE_Alpha,mAlpha); return bundle; } /** * 恢复状态 * * @param parcelable Parcelable */ @OverrIDe protected voID onRestoreInstanceState(Parcelable parcelable) { if (parcelable instanceof Bundle) { Bundle bundle = (Bundle) parcelable; mAlpha = bundle.getfloat(STATE_Alpha); super.onRestoreInstanceState(bundle.getParcelable(STATE_INSTANCE)); } else { super.onRestoreInstanceState(parcelable); } }}
然后在布局文件中声明使用,这里不需要每个自定义属性都使用到,因为我也提供了默认值
<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/ID_vIEwpager" androID:layout_wIDth="match_parent" androID:layout_height="0dp" androID:layout_weight="1" /> <linearLayout androID:layout_wIDth="match_parent" androID:layout_height="60dp" androID:background="@drawable/tab_background" androID:orIEntation="horizontal" androID:paddingBottom="3dp" androID:paddingtop="1dp"> <com.example.zy.myapplication.ShadeVIEw androID:ID="@+ID/ID_indicator_one" androID:layout_wIDth="0dp" androID:layout_height="match_parent" androID:layout_weight="1" androID:padding="5dp" app:icon="@drawable/weixin" app:text="微信" /> <com.example.zy.myapplication.ShadeVIEw androID:ID="@+ID/ID_indicator_two" androID:layout_wIDth="0dp" androID:layout_height="match_parent" androID:layout_weight="1" androID:padding="5dp" app:icon="@drawable/address_book" app:text="通讯录" /> <com.example.zy.myapplication.ShadeVIEw androID:ID="@+ID/ID_indicator_three" androID:layout_wIDth="0dp" androID:layout_height="match_parent" androID:layout_weight="1" androID:padding="5dp" app:icon="@drawable/discover" app:text="发现" /> <com.example.zy.myapplication.ShadeVIEw androID:ID="@+ID/ID_indicator_four" androID:layout_wIDth="0dp" androID:layout_height="match_parent" androID:layout_weight="1" androID:padding="5dp" app:icon="@drawable/me" app:text="我" /> </linearLayout></linearLayout>
因为主界面是VIEwPager,这里就需要一个Fragment子类
public class TabFragment extends Fragment { @OverrIDe public VIEw onCreateVIEw(LayoutInflater inflater,VIEwGroup container,Bundle savedInstanceState) { String mTitle = "微信"; if (getArguments() != null) { mTitle = getArguments().getString("Title","微信"); } TextVIEw textVIEw = new TextVIEw(getActivity()); textVIEw.setTextSize(25); textVIEw.setGravity(Gravity.CENTER); textVIEw.setText(mTitle); return textVIEw; }}
MainActivity代码如下,重点是对vIEwPager进行滑动监听,根据滑动偏移量来动态改变透明度Alpha,从而实现颜色渐变效果
public class MainActivity extends AppCompatActivity implements VIEwPager.OnPagechangelistener,VIEw.OnClickListener { private List<TabFragment> tabFragments; private List<ShadeVIEw> tabIndicators; private VIEwPager vIEwPager; private FragmentPagerAdapter adapter; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); initData(); vIEwPager = (VIEwPager) findVIEwByID(R.ID.ID_vIEwpager); vIEwPager.setAdapter(adapter); vIEwPager.addOnPagechangelistener(this); } private voID initData() { tabFragments = new ArrayList<>(); tabIndicators = new ArrayList<>(); String[] Titles = new String[]{"微信","通讯录","发现","我"}; for (String Title : Titles) { TabFragment tabFragment = new TabFragment(); Bundle bundle = new Bundle(); bundle.putString("Title",Title); tabFragment.setArguments(bundle); tabFragments.add(tabFragment); } adapter = new FragmentPagerAdapter(getSupportFragmentManager()) { @OverrIDe public int getCount() { return tabFragments.size(); } @OverrIDe public Fragment getItem(int arg0) { return tabFragments.get(arg0); } }; initTabIndicator(); } private voID initTabIndicator() { ShadeVIEw one = (ShadeVIEw) findVIEwByID(R.ID.ID_indicator_one); ShadeVIEw two = (ShadeVIEw) findVIEwByID(R.ID.ID_indicator_two); ShadeVIEw three = (ShadeVIEw) findVIEwByID(R.ID.ID_indicator_three); ShadeVIEw four = (ShadeVIEw) findVIEwByID(R.ID.ID_indicator_four); tabIndicators.add(one); tabIndicators.add(two); tabIndicators.add(three); tabIndicators.add(four); one.setonClickListener(this); two.setonClickListener(this); three.setonClickListener(this); four.setonClickListener(this); one.setIconAlpha(1.0f); } @OverrIDe public voID onClick(VIEw v) { resetTabsstatus(); switch (v.getID()) { case R.ID.ID_indicator_one: tabIndicators.get(0).setIconAlpha(1.0f); vIEwPager.setCurrentItem(0,false); break; case R.ID.ID_indicator_two: tabIndicators.get(1).setIconAlpha(1.0f); vIEwPager.setCurrentItem(1,false); break; case R.ID.ID_indicator_three: tabIndicators.get(2).setIconAlpha(1.0f); vIEwPager.setCurrentItem(2,false); break; case R.ID.ID_indicator_four: tabIndicators.get(3).setIconAlpha(1.0f); vIEwPager.setCurrentItem(3,false); break; } } /** * 重置Tab状态 */ private voID resetTabsstatus() { for (int i = 0; i < tabIndicators.size(); i++) { tabIndicators.get(i).setIconAlpha(0); } } /** * 如果是直接点击图标来跳转页面的话,position值为0到3,positionOffset一直为0.0 * 如果是通过滑动来跳转页面的话 * 假如是从第一页滑动到第二页 * 在这个过程中,positionOffset从接近0逐渐增大到接近1.0,滑动完成后又恢复到0.0,而position只有在滑动完成后才从0变为1 * 假如是从第二页滑动到第一页 * 在这个过程中,positionOffset从接近1.0逐渐减小到0.0,而position一直是0 * * @param position 当前页面索引 * @param positionOffset 偏移量 * @param positionOffsetPixels 偏移量 */ @OverrIDe public voID onPageScrolled(int position,float positionOffset,int positionOffsetPixels) { Log.e("TAG","position==" + position); Log.e("TAG","positionOffset==" + positionOffset); Log.e("TAG","positionOffsetPixels==" + positionOffsetPixels); if (positionOffset > 0) { ShadeVIEw leftTab = tabIndicators.get(position); ShadeVIEw rightTab = tabIndicators.get(position + 1); leftTab.setIconAlpha(1 - positionOffset); rightTab.setIconAlpha(positionOffset); } } @OverrIDe public voID onPageSelected(int position) { if (position == 2) { tabIndicators.get(position).setIconBitmap(this,R.drawable.discover_green); } else { tabIndicators.get(2).setIconBitmap(this,R.drawable.discover); } } @OverrIDe public voID onPageScrollStateChanged(int state) { }}
总结
以上所述是小编给大家介绍的AndroID 仿微信底部渐变Tab效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持!
总结以上是内存溢出为你收集整理的Android 仿微信底部渐变Tab效果全部内容,希望文章能够帮你解决Android 仿微信底部渐变Tab效果所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)