感谢 github的作者:wuyexiong

效果图(图片和文字都有渐变效果)

实现

主要用到自定义一个LinearLayout和ImageView

1.BottomIconView继承自ImageView

BottomIconView的作用是现在Tab中的图标,有根据滑动的偏移值显示渐变的图标。

package jfsl.view.view;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.Rect;

import android.util.AttributeSet;

import android.widget.ImageView;

/**

* 底部Tab图标类,

* 分正常的状态和选中的状态

* 根据滑动的偏移量改变alpha值

* 然后显示出来

*

* 感谢 wuyexiong

* Created by wuyexiong on 4/25/15.

* Modify by JFSL on 2016-11-20 20:05

*/

public class BottomIconView extends ImageView

{

public static final int START_POSITION = 0;

public static final int ALPHA_MAX = 255;

//画笔

private Paint mPaint;

//选中时的图标

private Bitmap mIconSelected;

//未选中时的图标

private Bitmap mIconNormal;

//选中时的矩形(限制绘制范围)

private Rect mRectSelected;

//未选中时的矩形(限制绘制范围)

private Rect mRectNormal;

//当前的alpha值

private int mAlphaCurrent = 0;

public BottomIconView(Context context)

{

super(context);

}

public BottomIconView(Context context,AttributeSet attrs)

{

super(context,attrs);

}

public BottomIconView(Context context,AttributeSet attrs,int defStyleAttr)

{

super(context,attrs,defStyleAttr);

}

/**

* 初始化

*

* @param normal 正常图标的id

* @param selected 选中的图标的id

*/

public final void init(int normal,int selected) throws Exception

{

mIconNormal = createBitmap(normal);

mIconSelected = createBitmap(selected);

//创建不了图片

if(mIconNormal == null || mIconSelected == null)

throw new Exception("icon id can not create1 bitmap");

//根据创建的位图创建对应的矩形

mRectNormal = new Rect(START_POSITION,START_POSITION,mIconNormal.getWidth(),mIconNormal.getHeight());

mRectSelected = new Rect(START_POSITION,START_POSITION,mIconSelected.getWidth(),mIconSelected.getHeight());

//画笔只要实例化就行,没有什么要求

mPaint = new Paint(1);

}

/**

* 根据资源id创建的位图

*

* @param resId 资源id

* @return 创建的位图

*/

private Bitmap createBitmap(int resId)

{

return BitmapFactory.decodeResource(getResources(),resId);

}

@Override

protected void onDraw(Canvas canvas)

{

super.onDraw(canvas);

//画笔为空,直接返回

if(mPaint == null)

return;

//设置当前选中图标的alpha值(逐渐减少)

mPaint.setAlpha(ALPHA_MAX - mAlphaCurrent);

canvas.drawBitmap(mIconNormal,null,mRectNormal,mPaint);

//设置目标图标的alpha值(逐渐减增大)

mPaint.setAlpha(mAlphaCurrent);

canvas.drawBitmap(mIconSelected,null,mRectSelected,mPaint);

}

/**

* 改变alpha值

*

* @param alpha

*/

public final void changeSelectedAlpha(int alpha)

{

mAlphaCurrent = alpha;

invalidate();

}

/**

* ViewPager切换时用到

*

* @param offset 偏移量

*/

public final void transformPage(float offset)

{

changeSelectedAlpha((int)(ALPHA_MAX * (1 - offset)));

}

}

2.底部Tab(BottomIndicator继承自LinearLayout)

package jfsl.view.view;

import android.animation.ArgbEvaluator;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.support.v4.view.PagerAdapter;

import android.support.v4.view.ViewPager;

import android.util.AttributeSet;

import android.view.LayoutInflater;

import android.view.View;

import android.widget.LinearLayout;

import android.widget.TextView;

import jfsl.view.R;

/**

* 底部指示器

* Github上的例子,拿来修改了下

* Created by wuyexiong on 4/25/15.

* @version 1.0

* @aduthor JFSL

* @date 2016/11/14

*/

public class BottomIndicator extends LinearLayout

{

public static final int ICON_INDEX_NORMAL = 0;

public static final int ICON_INDEX_SELECTED = 1;

public static final int DEFALUT_SELECTED_ITEM = 0;

public static final String COLOR_TEXT_NORMAL = "#FF999999";

public static final String COLOR_TEXT_SELECTED = "#FF46C01B";

//文字颜色渐变类

private ArgbEvaluator mColorEvaluator;

//正常文本的颜色

private int mTextNormalColor;

//选中时文本的颜色

private int mTextSelectedColor;

//最后的位置

private int mLastPosition;

//选中的位置

private int mSelectedPosition;

//选择的偏移量

private float mSelectionOffset;

//底部tab文本

private String mTitles[] = {"微信","通讯录","发现","我"};

//对应的图标

private int mIconRes[][] = {

{R.drawable.icon_main_home_normal,R.drawable.icon_main_home_selected},

{R.drawable.icon_main_category_normal,R.drawable.icon_main_category_selected},

{R.drawable.icon_main_service_normal,R.drawable.icon_main_service_selected},

{R.drawable.icon_main_mine_normal,R.drawable.icon_main_mine_selected}};

//Item数组

private View[] mItemLayout;

//关联的ViewPager

private ViewPager mViewPager;

public BottomIndicator(Context context)

{

this(context,null);

}

public BottomIndicator(Context context,AttributeSet attrs)

{

this(context,attrs,0);

}

public BottomIndicator(Context context,AttributeSet attrs,int defStyleAttr)

{

super(context,attrs,defStyleAttr);

//初始化

init();

}

/**

* 初始化

*/

private void init()

{

//实例化颜色渐变类

mColorEvaluator = new ArgbEvaluator();

//选中和未选中的文本的颜色

mTextNormalColor = Color.parseColor(COLOR_TEXT_NORMAL);

mTextSelectedColor = Color.parseColor(COLOR_TEXT_SELECTED);

}

public void setViewPager(ViewPager viewPager)

{

//清空所有的view

removeAllViews();

mViewPager = viewPager;

//viewapger数据不为空

if(viewPager != null && viewPager.getAdapter() != null)

{

//设置监听

viewPager.addOnPageChangeListener(new ViewPagerListener());

try

{

populateTabLayout();

}catch(Exception e)

{

e.printStackTrace();

}

}

}

/**

* 生成底部tab

*/

private void populateTabLayout() throws Exception

{

final PagerAdapter adapter = mViewPager.getAdapter();

final OnClickListener tabClickListener = new TabClickListener();

//根据adapter中item 的数量生成数组

mItemLayout = new View[ adapter.getCount() ];

//遍历

for(int i = 0;i < adapter.getCount();i++)

{

final View tabView = LayoutInflater.from(getContext()).inflate(R.layout.item_bottom_tab,this,false);

//找不到对应的布局

if(tabView == null)

throw new IllegalStateException("tabView is null.");

mItemLayout[ i ] = tabView;

//图标

BottomIconView iconView = (BottomIconView)tabView.findViewById(R.id.bottom_tab_icon);

iconView.init(mIconRes[ i ][ ICON_INDEX_NORMAL ],mIconRes[ i ][ ICON_INDEX_SELECTED ]);

//文字

TextView textView = (TextView)tabView.findViewById(R.id.bottom_tab_text);

textView.setText(mTitles[ i ]);

//改变宽度和权重 item平分屏幕

LayoutParams lp = (LayoutParams)tabView.getLayoutParams();

lp.width = 0;

lp.weight = 1;

tabView.setOnClickListener(tabClickListener);

addView(tabView);

if(i == mViewPager.getCurrentItem())

{

iconView.transformPage(DEFALUT_SELECTED_ITEM);

tabView.setSelected(true);

textView.setTextColor(mTextSelectedColor);

}

}

}

/**

* 内部ViewPager监听

* 外面想监听,自定义一个

*/

private class ViewPagerListener implements ViewPager.OnPageChangeListener

{

//状态

private int mScrollState;

@Override

public void onPageScrolled(int position,float positionOffset,int positionOffsetPixels)

{

onViewPagerPageChanged(position,positionOffset);

}

@Override

public void onPageSelected(int position)

{

for(int i = 0;i < getChildCount();i++)

{

//图标

BottomIconView bottomIcon = ((BottomIconView)mItemLayout[ i ].findViewById(R.id.bottom_tab_icon));

bottomIcon.transformPage(position == i ? 0 : 1);

//文本

TextView bottomText = ((TextView)mItemLayout[ i ].findViewById(R.id.bottom_tab_text));

bottomText.setTextColor(position == i ? mTextSelectedColor : mTextNormalColor);

}

if(mScrollState == ViewPager.SCROLL_STATE_IDLE)

{

onViewPagerPageChanged(position,0f);

}

//设置选中项

for(int i = 0, size = getChildCount();i < size;i++)

{

getChildAt(i).setSelected(position == i);

}

}

@Override

public void onPageScrollStateChanged(int state)

{

mScrollState = state;

}

}

/**

* ViewPager的item改变

*

* @param position

* @param positionOffset

*/

private void onViewPagerPageChanged(int position,float positionOffset)

{

mSelectedPosition = position;

mSelectionOffset = positionOffset;

if(positionOffset == 0f && mLastPosition != mSelectedPosition)

{

mLastPosition = mSelectedPosition;

}

invalidate();

}

/**

* 绘制方法

*

* @param canvas

*/

@Override

protected void onDraw(Canvas canvas)

{

super.onDraw(canvas);

final int childCount = getChildCount();

if(childCount > 0)

{

if(mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1))

{

View selectedTab = getChildAt(mSelectedPosition);

View nextTab = getChildAt(mSelectedPosition + 1);

View selectedIconView = ((LinearLayout)selectedTab).getChildAt(0);

View nextIconView = ((LinearLayout)nextTab).getChildAt(0);

View selectedTextView = ((LinearLayout)selectedTab).getChildAt(1);

View nextTextView = ((LinearLayout)nextTab).getChildAt(1);

//draw icon alpha

if(selectedIconView instanceof BottomIconView && nextIconView instanceof BottomIconView)

{

((BottomIconView)selectedIconView).transformPage(mSelectionOffset);

((BottomIconView)nextIconView).transformPage(1 - mSelectionOffset);

}

/**

* 使用ArgbEvaluator类来控制文本的颜色渐变

*/

//draw text color

Integer selectedColor = (Integer)mColorEvaluator.evaluate(mSelectionOffset,

mTextSelectedColor,

mTextNormalColor);

Integer nextColor = (Integer)mColorEvaluator.evaluate(1 - mSelectionOffset,

mTextSelectedColor,

mTextNormalColor);

if(selectedTextView instanceof TextView && nextTextView instanceof TextView)

{

((TextView)selectedTextView).setTextColor(selectedColor);

((TextView)nextTextView).setTextColor(nextColor);

}

}

}

}

/**

* Tab的Item点击

*/

private class TabClickListener implements OnClickListener

{

@Override

public void onClick(View v)

{

for(int i = 0;i < getChildCount();i++)

{

if(v == getChildAt(i))

{

mViewPager.setCurrentItem(i,false);

return;

}

}

}

}

}

3.主布局(ViewPager+BottomIndicator)

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/id_viewPager"

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_weight="1">

android:id="@+id/id_bottom_indicator"

android:layout_width="match_parent"

android:layout_height="56dp"

android:background="@drawable/bg_tab_bottom">

4.tab item的布局(BottomIconView+TextView)

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center"

android:background="@null"

android:orientation="vertical">

android:id="@+id/bottom_tab_icon"

android:layout_width="32dp"

android:layout_height="28dp"

android:layout_gravity="center_horizontal"

android:scaleType="fitCenter" />

android:id="@+id/bottom_tab_text"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center_horizontal"

android:textSize="12sp" />

5.Tab的背景 layer-list可以将多个图片按照顺序层叠起来

背景不能去掉,去掉之后看不到渐变的效果

android:dither="true"

android:shape="rectangle">

android:dither="true"

android:shape="rectangle">

6.测试的Activity

package jfsl.view;

import android.os.Bundle;

import android.support.v4.app.FragmentPagerAdapter;

import android.support.v4.view.ViewPager;

import android.support.v7.app.AppCompatActivity;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import jfsl.view.adapter.TopViewPagerAdapter;

import jfsl.view.fragment.SimpleFragment;

import jfsl.view.view.BottomIndicator;

public class MainActivity extends AppCompatActivity

{

private ViewPager mViewPager;

private List mTitles = Arrays.asList("Fragment-->微信","Fragment-->通讯录","Fragment-->发现","Fragment-->我");

private List mFragments = new ArrayList<>();

private FragmentPagerAdapter mPagerAdapter;

private BottomIndicator mIndicator;

@Override

protected void onCreate(Bundle savedInstanceState)

{

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_bottom_tab);

initViews();

initDatas();

initEvent();

}

private void initViews()

{

mViewPager = (ViewPager)findViewById(R.id.id_viewPager);

mIndicator = (BottomIndicator)findViewById(R.id.id_bottom_indicator);

}

private void initDatas()

{

for(String title : mTitles)

{

mFragments.add(SimpleFragment.newInstance(title));

}

mPagerAdapter = new TopViewPagerAdapter(getSupportFragmentManager(),this,mFragments);

mViewPager.setAdapter(mPagerAdapter);

mIndicator.setViewPager(mViewPager);

}

private void initEvent()

{

}

}

7.adapter(ViewPager的Adapter)

package jfsl.view.adapter;

import android.content.Context;

import android.support.v4.app.Fragment;

import android.support.v4.app.FragmentManager;

import android.support.v4.app.FragmentPagerAdapter;

import java.util.List;

import jfsl.view.fragment.SimpleFragment;

/**

* @version 1.0

* @aduthor JFSL

* @date 2016/11/12 0012

*/

public class TopViewPagerAdapter extends FragmentPagerAdapter

{

private Context mContext;

private List mFragments;

public TopViewPagerAdapter(FragmentManager fm,Context context,List fragments)

{

super(fm);

mContext = context;

mFragments = fragments;

}

@Override

public Fragment getItem(int position)

{

return mFragments.get(position);

}

@Override

public int getCount()

{

return mFragments.size();

}

}

8.创建Fragment(根据String创建一个简单的Fragment)

package jfsl.view.fragment;

import android.os.Bundle;

import android.support.annotation.Nullable;

import android.support.v4.app.Fragment;

import android.view.Gravity;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.TextView;

/**测试用的Fragment

* @version 1.0

* @aduthor JFSL

* @date 2016/11/12 0012

*/

public class SimpleFragment extends Fragment

{

public static final String BUNDLE_TITLE = "title";

private String mTitle;

@Nullable

@Override

public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState)

{

Bundle bundle = getArguments();

if(bundle != null)

mTitle = bundle.getString(BUNDLE_TITLE);

TextView textView = new TextView(getActivity());

textView.setText(mTitle);

textView.setGravity(Gravity.CENTER);

return textView;

}

/**

* 获取实例

* @param title

* @return

*/

public static SimpleFragment newInstance(String title)

{

Bundle bundle = new Bundle();

bundle.putString(BUNDLE_TITLE,title);

SimpleFragment fragment = new SimpleFragment();

fragment.setArguments(bundle);

return fragment;

}

}

图标素材( 放在xxhdpi)

android 微信布局 字体,【Android】底部Tab+ViewPager(仿微信界面)相关推荐

  1. Android显示九宫图(自定义圆角,仿微信九宫格图)

    详细解析Android显示九宫图(自定义圆角,仿微信九宫格图) 这是一个自定义九宫格图片框架,里面有设置圆角大小,还有当图片一张的时候控件自定义的大小,图片的间隔,四张图片的时候图片自定义为两行两列等 ...

  2. android源代码居中字体,Android (布局优化) TextView实现drawable图标大小 位置与第一行文本居中...

    先看大众点评的购买须知 大众.png 如上图,需求在每条提示语句前加一个小圆点,我刚看到需求就想到用 android:drawableLeft 来做,可做完发现:当TextView内容为单行的时候是没 ...

  3. android 模仿微信布局,【Android初学者】框架布局:仿微信页面制作

    学习Android有一段时间了,跟大家分享一下经验吧! 如果有错误的地方,有更好的方法,麻烦大家留言指导! 工具:studio2.2,虚拟机版本:4.3,API 18(感觉比5.1的稳定啊!) 例子是 ...

  4. android ui布局适配,Android适配全面总结(一)----屏幕适配

    前言 Android适配是一个老生常谈的问题,很多程序员觉得很恶心,不愿意做适配,但是又不得不做.然后老板说,这位兄弟,做好了,今天晚饭给你加个鸡腿,然后程序员开始找各种资料,忙活起来了,最终在苦逼的 ...

  5. android相对布局代码,Android基础_3 Activity相对布局(示例代码)

    相对布局要比前面讲的线性布局和表格布局要灵活一些,所以平常用得也是比较多的.相对布局控件的位置是与其周围控件的位置相关的,从名字可以看出来,这些位置都是相对的,确定出了其中一个控件的位置就可以确定另一 ...

  6. android百分比布局失效,Android 百分比布局库【原创】

    为了解决android手机适配问题,我们经常想如果可以按照百分比的方式进行界面布局,这样适配各种屏幕就简单多了吧!现在谷歌正式提供百分比布局支持库(android-support-percent-li ...

  7. android 仿微信选取相册_Android--选择图片(仿微信发朋友圈)第一篇

    这篇博客主要写仿微信朋友圈选择图片发朋友圈.整个功能包括加载图片,显示图片.相册文件夹.预览图片,九宫格显示已经选择好的图片等等,大概会有三篇博客. 效果图 看上面的图,加载图片肯定是异步加载,耗时任 ...

  8. android studio 布局嵌套,Android Studio实战 - 设计布局之嵌套布局

    通过布局的嵌套可以创造出复杂的设计.如果想要美化之前的个人信息界面,可以采用 将 LinearLayout嵌入到RelativeLayout中的方法.这个布局包含一个在线状态标签和一 个描述字段. 单 ...

  9. android app替换字体,Android APP更换字体策略精要

    前言 近期项目需要在我们的APP中使用指定的字体库.经过搜集资料,研读源码,和别人探讨请教,最终产出了一些比较好的方案.不敢专享,写成文章分享出来,希望对大家的实际开发工作有所帮助.喜欢探讨Andro ...

最新文章

  1. 解决IDEA中进行maven install报:系统资源不足的问题
  2. 支付宝 android 2.3,app被拒记录-2.3-包含支付宝
  3. 句句真研—每日长难句打卡Day13
  4. 2021年中国单索运动滑轮市场趋势报告、技术动态创新及2027年市场预测
  5. vue获取接口数据_c#中HttpWebRequest调用接口获取数据
  6. 【Tensorflow2.0】关于制作标签遇到的问题小结
  7. linux 登录直接进入系统,Linux登录和推出系统入门教程
  8. 《初识Scratch》教学设计
  9. 关于DNF的多媒体包NPK文件的那些事儿(9) - IMGV6
  10. Excel——公式与函数基础
  11. 帆软报表更新到服务器控件展示不出来_如何报表控件FineReport实现自定义附件处理...
  12. ecshop模板支持php,ecshop模板支持php数据运算的代码实例
  13. #51CTO学院四周年# 我和51cto的故事
  14. iOS 10诸如相机、相册、通讯录、麦克风、定位权限设置,防止奔溃或上架被拒
  15. 解决Android在更新安装包时出现“未安装应用”的情况
  16. linux TC命令使用总结
  17. Python:利用高德API获取公交路线并可视化
  18. k3 审核流程图_K3单据使用解释及流程图明细
  19. python一对小兔子一年后长大成大兔子;一对大兔子每半年生一对小兔子。大兔子的繁殖期为4年,兔子的寿命是6年。假定第一年年初投放了一对小兔子,试编程计算,第n年末(不考虑死亡情况)总共会有多少对兔子
  20. 【C进阶】第十篇——数据在内存中的存储

热门文章

  1. GraphQL API 的查询语言
  2. Electron开发桌面应用
  3. GitLab 8.9 新增文件锁 和 U2F硬件支持
  4. java 调用gpu_GPU使用设置
  5. linux下查看ntp对时的命令,linux 查看服务器时间命令
  6. 学校运动会广播稿计算机,学校运动会广播稿【五篇】
  7. 运维安全加固规范_DBA如何巧用“三十六计”保障数据库安全?
  8. LR中并发用户和集合点
  9. C#内存共享通讯示例
  10. 6.表单提交,input键盘变搜索,有关自定义属性input操作