撸一个微信的底部Tab切换透明度变化效果

微信6.0的时候就出现有了底部Tab切换透明度变化的效果,趁着周末也抽空来实现一下,其实十分简单,我们先来看一下效果:

嗯,没错,又是偷的图

原图来自:http://upload-images.jianshu.io/upload_images/2552605-8cf01f84f3a344d3?imageMogr2/auto-orient/strip
效果大概就跟上图一模一样吧。,所以我就懒得自己录制了。
首先我们拿到这一个需求,操起我们的笔和纸,将你知道的一些用于实现的思路写下来,要养成一个良好的习惯哦。

解剖后大概能知道:1,ViewPager和Fragment结合使用(此处用FragmentPagerAdapter)
2,可能需要两套图,选中状态套餐A(就是那个绿帽子颜色的),未选中时的套餐B(被绿后世界都变成灰色了)
3,需要动态的获取position以及positionOffset,然后拿到左右两个View,设置positionOffset (这个值时关键!!!);
4,处理点击时图片文字切换
哇靠,原来就这么简单。

那么这里最骚的操作在哪里呢,就是重中之重的第三步操作了!!
有些同学可能会疑问positionOffset是什么,怎么用?

这里给大家简单通过一道数学题目来解释一下,我们大家都解过方程式吧,such as:y=1-x;我们画个图,大概长这样:

y随着x的递增而减小。

其实我们的滑动处理和这个函数的一模一样的,我们当前选中项的绿色透明度为1,下一个Tab的值为0(Y),positionOffset的值即为X。


好的,本文分析到此结束!

同学可以下课自己实现了

我也偷偷打开我的Android studio实现了一波:

首先我们看xml代码,我们需要在xml中通过相对布局或者FramLayout来将绿色图套在灰色图之上!!!(因为无论透明度如何发现改变,只是针对绿色图片,我!们!底!部!的!灰!色!图!片!一!直!都!在!)。

我们每个tab都应该时这样处理的,这里给出一个,另外三个是一样的。文末给出完整代码

           <RelativeLayout android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical"
        android:id="@+id/rl_mine"
        android:layout_width="0dp">

        <!--正常显示时的图片-->
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/mine_normal" />
        <!--选中时的图片-->
        <ImageView
            android:id="@+id/mine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/mine_selected" />
        <!--正常显示的文字颜色-->
        <TextView
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/mine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="我"
            />
        <!--选中时显示的文字颜色-->
        <TextView
            android:textColor="#46c01b"
            android:id="@+id/mine_tv"
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/mine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="我"
            />
    </RelativeLayout>
xml分界线,接下来是Java了

接下来好戏登场了,我们开始编写Java代码啦。

首先创建一个TabFragment,大致如下:

public class TabFragment extends Fragment{

//默认显示文字
private String content ="default";
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    /**
     * 通过Arguments获取传来的参数,与getActivity.getIntent.getXXX("xxx")相比,此方式实现了与Activity的解耦
     * 使得我们的TabFragment可以复用。
     */
    if (getArguments()!=null){
        content = getArguments().getString("content");
    }
    
    TextView textView = new TextView(getContext());
    textView.setGravity(Gravity.CENTER);
    textView.setText(content);
    textView.setTextSize(26);
    textView.setBackgroundColor(Color.parseColor("#ffffffff"));
    return textView;
}}

Fragment创建好了,还是非常简单的,无非就是一个TextView,这里为了方便复用Fragment,不通过编写多套布局的方式一个一个Inflate。

Activity:

第一步,findById,这里我是用ButterKnife插件,就不一一find了。
@BindView(R.id.viewPager)
ViewPager viewPager;//ViewPager
@BindView(R.id.home)
ImageView home;//绿色的微信图片
@BindView(R.id.home_tv)
TextView homeTv;//绿色的微信文字
@BindView(R.id.rl_home)
RelativeLayout rlHome;
@BindView(R.id.category)
ImageView category;//绿色的通讯录图片
@BindView(R.id.category_tv)
TextView categoryTv;//绿色的通讯录文字
@BindView(R.id.rl_category)
RelativeLayout rlCategory;
@BindView(R.id.service)
ImageView service;//绿色的发现图片
@BindView(R.id.service_tv)
TextView serviceTv;//绿色的发现文字
@BindView(R.id.rl_service)
RelativeLayout rlService;
@BindView(R.id.mine)
ImageView mine;//绿色的我图片
@BindView(R.id.mine_tv)
TextView mineTv;//绿色的我文字
@BindView(R.id.rl_mine)
RelativeLayout rlMine;
private MyPagerAdapter adapter;//适配器

private List<Fragment> mTabs = new ArrayList<>();//Fragment集合
private List<ImageView> images = new ArrayList<>();//绿色图片集合
private List<TextView> texts = new ArrayList<>();//绿色文字集合
private String[] mContents = new String[]{"微信", "通讯录", "发现", "我"};//Fragment中TextView显示内容

第二步:初始化数据:

private void initData() {

    //创建TabFragment
    for (int i = 0; i < mContents.length; i++) {
        TabFragment tabFragment = new TabFragment();
        Bundle bundle = new Bundle();
        bundle.putString("content", mContents[i]);
        tabFragment.setArguments(bundle);
        mTabs.add(tabFragment);
    }
    images.add(home);
    images.add(category);
    images.add(service);
    images.add(mine);

    texts.add(homeTv);
    texts.add(categoryTv);
    texts.add(serviceTv);
    texts.add(mineTv);
    setselectedTabColor(0);
}

上面创建了四个TabFragment,并且将我们的绿色图片和绿色文字分别添加到集合中,方便后期做切换处理。

第三步:编写FragmentPagerAdapter并绑定。

private class MyPagerAdapter extends FragmentPagerAdapter {

    //构造方法
    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }
    //返回当前Fragment
    @Override
    public Fragment getItem(int position) {
        return mTabs.get(position);
    }

    //返回Fragment个数
    @Override
    public int getCount() {
        return mTabs.size();
    }
}

记得在Activity中的onCreate方法中绑定适配器:
viewPager.setAdapter(adapter = new MyPagerAdapter(getSupportFragmentManager()));
viewPager.setOnPageChangeListener(this);

第四步:实现ViewPager的onPagerChangeListener方法
implements ViewPager.OnPageChangeListener

第五步:实现底部Tab选中时图片和文字的切换:

private void setselectedTabColor(int pos) {

    images.get(0).setAlpha(0f);
    images.get(1).setAlpha(0f);
    images.get(2).setAlpha(0f);
    images.get(3).setAlpha(0f);

    texts.get(0).setAlpha(0f);
    texts.get(1).setAlpha(0f);
    texts.get(2).setAlpha(0f);
    texts.get(3).setAlpha(0f);
    images.get(pos).setAlpha(1f);
    texts.get(pos).setAlpha(1f);
}

第六步:实现透明度变化方法:

private void changeAlpha(int pos, float posOffset) {

    int nextIndex = pos + 1;
    if (posOffset > 0) {
        //设置tab的颜色渐变效果
        images.get(pos).setAlpha(1f - posOffset);
        images.get(nextIndex).setAlpha(posOffset);
        texts.get(pos).setAlpha(1f-posOffset);
        texts.get(nextIndex).setAlpha(posOffset);
    }
}

第七步:重写OnPageChangeListener的onPageScrolled,onPageSelected的方法:

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    changeAlpha(position, positionOffset);
}

@Override
public void onPageSelected(int position) {

    switch (position) {
        case 0:
            setselectedTabColor(0);
            break;
        case 1:
            setselectedTabColor(1);
            break;
        case 2:
            setselectedTabColor(2);
            break;
        case 3:
            setselectedTabColor(3);
            break;

    }
}

@Override
public void onPageScrollStateChanged(int state) {

}

最后一步:处理点击事件中Fragment切换和底部Tab切换:

public void onViewClicked(View view) {
    switch (view.getId()) {
        case R.id.rl_home:
            viewPager.setCurrentItem(0, false);
            setselectedTabColor(0);
            break;
        case R.id.rl_category:
            viewPager.setCurrentItem(1, false);
            setselectedTabColor(1);
            break;
        case R.id.rl_service:
            viewPager.setCurrentItem(2, false);
            setselectedTabColor(2);
            break;
        case R.id.rl_mine:
            viewPager.setCurrentItem(3, false);
            setselectedTabColor(3);
            break;
    }
}

这里需要注意的时viewPager.setCurrentItem方法,第二个参数为是否启用ViewPager滑动时的动画效果,我们这里因为有透明度的变化,但它只是在滑动时才具有的,点击时不需要,不然会有很糟糕的视觉效果!!!同学可以试一下。

完成了,喝杯啤酒,兄弟

这里给出完整代码:
xml中:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.xjf.wxswitchdemo.MainActivity">

<android.support.v4.view.ViewPager
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    tools:layout_editor_absoluteY="0dp"
    tools:layout_editor_absoluteX="8dp"
    ></android.support.v4.view.ViewPager>

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="#888"
    tools:layout_editor_absoluteY="0dp"
    tools:layout_editor_absoluteX="8dp" />

<LinearLayout
    android:layout_width="match_parent"
    android:gravity="center"
    android:orientation="horizontal"
    android:layout_height="55dp">

    <RelativeLayout
        android:id="@+id/rl_home"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/home_normal" />

        <ImageView
            android:id="@+id/home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/home_selected" />

        <TextView
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="微信"
            />

        <TextView
            android:textColor="#46c01b"
            android:id="@+id/home_tv"
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/home"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="微信"
            />

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_category"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/category_normal" />

        <ImageView
            android:id="@+id/category"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/category_selected" />

        <TextView
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/category"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="通讯录"
            />

        <TextView
            android:textColor="#46c01b"
            android:id="@+id/category_tv"
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/category"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="通讯录"
            />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_service"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/service_normal" />

        <ImageView
            android:id="@+id/service"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/service_selected" />

        <TextView
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/service"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="发现"
            />

        <TextView
            android:textColor="#46c01b"
            android:id="@+id/service_tv"
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/service"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="发现"
            />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/rl_mine"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <!--正常显示时的图片-->
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/mine_normal" />
        <!--选中时的图片-->
        <ImageView
            android:id="@+id/mine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@mipmap/mine_selected" />
        <!--正常显示的文字颜色-->
        <TextView
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/mine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="我"
            />
        <!--选中时显示的文字颜色-->
        <TextView
            android:textColor="#46c01b"
            android:id="@+id/mine_tv"
            android:layout_centerHorizontal="true"
            android:layout_below="@+id/mine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="我"
            />
    </RelativeLayout>

</LinearLayout></LinearLayout>

MainActivity中代码:

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {


@BindView(R.id.viewPager)
ViewPager viewPager;//ViewPager
@BindView(R.id.home)
ImageView home;//绿色的微信图片
@BindView(R.id.home_tv)
TextView homeTv;//绿色的微信问题
@BindView(R.id.rl_home)
RelativeLayout rlHome;
@BindView(R.id.category)
ImageView category;//绿色的通讯录图片
@BindView(R.id.category_tv)
TextView categoryTv;//绿色的通讯录文字
@BindView(R.id.rl_category)
RelativeLayout rlCategory;
@BindView(R.id.service)
ImageView service;//绿色的发现图片
@BindView(R.id.service_tv)
TextView serviceTv;//绿色的发现文字
@BindView(R.id.rl_service)
RelativeLayout rlService;
@BindView(R.id.mine)
ImageView mine;//绿色的我图片
@BindView(R.id.mine_tv)
TextView mineTv;//绿色的我文字
@BindView(R.id.rl_mine)
RelativeLayout rlMine;
private MyPagerAdapter adapter;//适配器

private List<Fragment> mTabs = new ArrayList<>();//Fragment集合
private List<ImageView> images = new ArrayList<>();//绿色图片集合
private List<TextView> texts = new ArrayList<>();//绿色文字集合
private String[] mContents = new String[]{"微信", "通讯录", "发现", "我"};//Fragment中TextView显示内容

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
    initData();
    viewPager.setAdapter(adapter = new MyPagerAdapter(getSupportFragmentManager()));
    viewPager.setOnPageChangeListener(this);
}

private void initData() {
    //创建TabFragment
    for (int i = 0; i < mContents.length; i++) {
        TabFragment tabFragment = new TabFragment();
        Bundle bundle = new Bundle();
        bundle.putString("content", mContents[i]);
        tabFragment.setArguments(bundle);
        mTabs.add(tabFragment);
    }
    images.add(home);
    images.add(category);
    images.add(service);
    images.add(mine);

    texts.add(homeTv);
    texts.add(categoryTv);
    texts.add(serviceTv);
    texts.add(mineTv);
    setselectedTabColor(0);
}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    changeAlpha(position, positionOffset);
}

@Override
public void onPageSelected(int position) {

    switch (position) {
        case 0:
            setselectedTabColor(0);
            break;
        case 1:
            setselectedTabColor(1);
            break;
        case 2:
            setselectedTabColor(2);
            break;
        case 3:
            setselectedTabColor(3);
            break;

    }
}

@Override
public void onPageScrollStateChanged(int state) {

}


private void changeAlpha(int pos, float posOffset) {

    int nextIndex = pos + 1;
    if (posOffset > 0) {
        //设置tab的颜色渐变效果
        images.get(pos).setAlpha(1f - posOffset);
        images.get(nextIndex).setAlpha(posOffset);
        texts.get(pos).setAlpha(1f-posOffset);
        texts.get(nextIndex).setAlpha(posOffset);
    }
}

;


private void setselectedTabColor(int pos) {

    images.get(0).setAlpha(0f);
    images.get(1).setAlpha(0f);
    images.get(2).setAlpha(0f);
    images.get(3).setAlpha(0f);

    texts.get(0).setAlpha(0f);
    texts.get(1).setAlpha(0f);
    texts.get(2).setAlpha(0f);
    texts.get(3).setAlpha(0f);
    images.get(pos).setAlpha(1f);
    texts.get(pos).setAlpha(1f);
}

private class MyPagerAdapter extends FragmentPagerAdapter {

    //构造方法
    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }
    //返回当前Fragment
    @Override
    public Fragment getItem(int position) {
        return mTabs.get(position);
    }

    //返回Fragment个数
    @Override
    public int getCount() {
        return mTabs.size();
    }
}

@OnClick({R.id.rl_home, R.id.rl_category, R.id.rl_service, R.id.rl_mine})
public void onViewClicked(View view) {
    switch (view.getId()) {
        case R.id.rl_home:
            viewPager.setCurrentItem(0, false);
            setselectedTabColor(0);
            break;
        case R.id.rl_category:
            viewPager.setCurrentItem(1, false);
            setselectedTabColor(1);
            break;
        case R.id.rl_service:
            viewPager.setCurrentItem(2, false);
            setselectedTabColor(2);
            break;
        case R.id.rl_mine:
            viewPager.setCurrentItem(3, false);
            setselectedTabColor(3);
            break;
    }
}}

你以为这样就结束了吗?不是这样的,装逼还没有结束。


接下来我们自定义一个透明度自动变化的Tab容器控件!!!没错,其实思路和之前类似,只不过是自定义控件而已。那么我们就直接开始干了!!!!!!!!!!!!!

首先是定义一个透明度可以改变的ImageView;

public class TabIconView extends ImageView{

private Paint mPaint;
//选中时bitmap
private Bitmap mSelectedIcon;
//正常状态下bitmap
private Bitmap mNormalIcon;

//focus bitmap矩阵
private Rect mSelectedRect;
// normal bitmap矩阵
private Rect mNormalRect;
/** 当前选择项(mSelectedIcon)透明度
 * mNormalIcon透明度即为 255 - mSelectedAlpha*/
private int mSelectedAlpha = 0;

public TabIconView(Context context) {
    this(context,null);
}

public TabIconView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs,0);
}

public TabIconView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

/**
 * 初始化资源图片bitmap及相关绘制对象
 * @param normal
 * @param selected
 * @param width
 * @param height
 */
public final void init(int normal,int selected,int width,int height){
    this.mNormalIcon = BitmapFactory.decodeResource(getResources(),normal);
    this.mSelectedIcon = BitmapFactory.decodeResource(getResources(),selected);
    this.mNormalRect = new Rect(0,0,width,height);
    this.mSelectedRect = new Rect(0,0,width,height);
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//设置画笔抗锯齿
};

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mPaint==null){
        return;
    }
    mPaint.setAlpha(255-this.mSelectedAlpha);
    canvas.drawBitmap(mNormalIcon,null,mNormalRect,mPaint);
    mPaint.setAlpha(mSelectedAlpha);
    canvas.drawBitmap(mSelectedIcon,null,mSelectedRect,mPaint);
}

/**
 * 改变透明度
 * @param alpha
 */
public final void changeSelectedAlpha(int alpha){
    mSelectedAlpha = alpha;
    invalidate();
}


/**
 * 改变透明度百分比
 * @param offset 百分比
 */
public final void offsetChanged(float offset) {
    changeSelectedAlpha((int) (255 * (1 - offset)));
}}

接下来撸一个Tab容器。

public class TabContainerView extends LinearLayout {

private ViewPager mViewPager;
private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;

/** 默认颜色*/
private int mTextNormalColor;
/** 选中时颜色值*/
private int mTextSelectedColor;

/** 前一次选择位置*/
private int mLastPosition;
/** 当前选中位置*/
private int mSelectedPosition;
/**选择偏移位置 */
private float mSelectionOffset;

/** tab 标题*/
private String[] mTitles;
/** tab icon集合*/
private int[][] mIconRes;

/** tab item 视图集合*/
private View[] mTabView;

/** 布局文件id*/
private int mLayoutId;
/** textView 控件id*/
private int mTextViewId;
/** icon 控件id*/
private int mIconVIewId;

/**icon宽度*/
private int mIconWidth;
/**icon高度*/
private int mIconHeight;

/** 是否显示过渡颜色效果*/
private boolean mShowTransitionColor = true;

public TabContainerView(Context context) {
    this(context, null);
}

public TabContainerView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public void initContainer (String[] titles, int[][] iconsRes, int[] colors, boolean showTransitionColor) {
    this.mTitles = titles;
    this.mIconRes = iconsRes;
    this.mTextNormalColor = getResources().getColor(colors[0]);
    this.mTextSelectedColor = getResources().getColor(colors[1]);
    this.mShowTransitionColor = showTransitionColor;
}

/**
 * 设置布局文件及相关控件id
 * @param layout layout布局文件 id
 * @param iconId ImageView 控件 id id <=0 时不显示
 * @param textId TextView 控件 id id <=0 时不显示
 * @param width  icon 宽度
 * @param height icon 高度
 */
public void setContainerLayout (int layout, int iconId, int textId, int width, int height) {
    mLayoutId = layout;
    mTextViewId = textId;
    mIconVIewId = iconId;
    mIconWidth = width;
    mIconHeight = height;
}

/**
 * <p>设置布局文件及相关控件id --只有文本</p>
 * @param layout layout布局文件 id
 * @param textId TextView 控件 id
 * @param width  icon 宽度
 * @param height icon 高度
 */
public void setSingleTextLayout (int layout, int textId, int width, int height) {
    setContainerLayout(layout, 0, textId, width, height);

}

/**
 * <p>设置布局文件及相关控件id</p>
 * @param layout layout布局文件 id
 * @param iconId ImageView 控件 id
 * @param width  icon 宽度
 * @param height icon 高度
 */
public void setSingleIconLayout (int layout, int iconId, int width, int height) {
    setContainerLayout(layout, iconId, 0, width,  height);
}

public void setViewPager(ViewPager viewPager) {
    removeAllViews();
    mViewPager = viewPager;
    if (viewPager != null && viewPager.getAdapter() != null) {
        viewPager.addOnPageChangeListener(new InternalViewPagerListener());
        addTabViewToContainer();
    }
}

/**
 * <p>添加tab view到当前容器</p>
 */
private void addTabViewToContainer() {
    final PagerAdapter adapter = mViewPager.getAdapter();
    mTabView = new View[adapter.getCount()];

    for (int index = 0, len = adapter.getCount(); index < len; index++) {

        final View tabView = LayoutInflater.from(getContext()).inflate(mLayoutId, this, false);
        mTabView[index] = tabView;

        /*tabIconView初始化*/
        TabIconView iconView = null;
        if (mIconVIewId > 0) {
            iconView = (TabIconView) tabView.findViewById(mIconVIewId);
            iconView.init(mIconRes[index][0], mIconRes[index][1], mIconWidth, mIconHeight);
        }

        /*tabTextView初始化*/
        TextView textView = null;
        if (mTextViewId > 0) {
            textView = (TextView) tabView.findViewById(mTextViewId);
            textView.setText(mTitles[index]);

        }

        /*设置宽度,等分container*/
        LayoutParams lp = (LayoutParams) tabView.getLayoutParams();
        lp.width = 0;
        lp.weight = 1;

        /*添加tab点击事件*/
        addTabOnClickListener(tabView, index);

        /*设置当前状态*/
        if (index == mViewPager.getCurrentItem()) {
            if (iconView != null) {
                iconView.offsetChanged(0);
            }
            tabView.setSelected(true);
            if (textView != null) {
                textView.setTextColor(mTextSelectedColor);
            }
        }

        addView(tabView);
    }
}

/**
 * <p>viewPager滑动改变监听事件</p>
 */
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
    private int mScrollState;

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        onViewPagerPageChanged(position, positionOffset);

        if (mViewPagerPageChangeListener != null) {
            mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
        }
    }

    @Override
    public void onPageSelected(int position) {

        /*完成滑动动作后更新每个Item TextView的颜色值以及ImageView的状态值*/
        for (int i = 0; i < getChildCount(); i++) {
            if (mIconVIewId > 0) {
                ((TabIconView) mTabView[i].findViewById(mIconVIewId)) .offsetChanged(position == i ? 0 : 1);
            }
            if (mTextViewId > 0) {
                ((TextView) mTabView[i].findViewById(mTextViewId)) .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);
        }


        if (mViewPagerPageChangeListener != null) {
            mViewPagerPageChangeListener.onPageSelected(position);
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        mScrollState = state;

        if (mViewPagerPageChangeListener != null) {
            mViewPagerPageChangeListener.onPageScrollStateChanged(state);
        }
    }
}

/**
 * viewpager滑动改变后更新当前container视图
 * @param position 当前选择position
 * @param positionOffset position 偏移量
 */
private void onViewPagerPageChanged(int position, float positionOffset) {
    mSelectedPosition = position;
    mSelectionOffset = positionOffset;
    if (positionOffset == 0f && mLastPosition != mSelectedPosition) {
        mLastPosition = mSelectedPosition;
    }
    invalidate();
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    final int childCount = getChildCount();
    if (childCount > 0) {
        /*当发生偏移时,绘制渐变区域*/
        if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1) && mShowTransitionColor) {

            /*获取当前tab和下一tab view */
            View selectedTab = getChildAt(mSelectedPosition);
            View nextTab = getChildAt(mSelectedPosition + 1);

            /*显示tab icon时,刷新各自view 透明度*/
            if (mIconVIewId > 0) {
                View selectedIconView = selectedTab.findViewById(mIconVIewId);
                View nextIconView = nextTab.findViewById(mIconVIewId);

                //draw icon alpha
                if (selectedIconView instanceof TabIconView && nextIconView instanceof TabIconView) {
                    ((TabIconView) selectedIconView).offsetChanged(mSelectionOffset);
                    ((TabIconView) nextIconView).offsetChanged(1 - mSelectionOffset);
                }
            }

             /*显示tab text,刷新各自view 透明度*/
            if  (mTextViewId > 0) {
                View selectedTextView = selectedTab.findViewById(mTextViewId);
                View nextTextView = nextTab.findViewById(mTextViewId);

                //draw text color
                Integer selectedColor = (Integer) evaluate(mSelectionOffset, mTextSelectedColor, mTextNormalColor);
                Integer nextColor = (Integer) evaluate(1 - mSelectionOffset, mTextSelectedColor, mTextNormalColor);

                if (selectedTextView instanceof TextView && nextTextView instanceof TextView) {
                    ((TextView) selectedTextView).setTextColor(selectedColor);
                    ((TextView) nextTextView).setTextColor(nextColor);
                }
            }

        }
    }
}

/**
 * tab item点击事件,点击时直接跳到对应view
 * @param view        View
 * @param position position
 */
private void addTabOnClickListener (View view, final int position) {
    OnClickListener listener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            mViewPager.setCurrentItem(position, false);
        }
    };
    view.setOnClickListener(listener);
}


public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
    mViewPagerPageChangeListener = listener;
}

/**
 * This function returns the calculated in-between value for a color
 * given integers that represent the start and end values in the four
 * bytes of the 32-bit int. Each channel is separately linearly interpolated
 * and the resulting calculated values are recombined into the return value.
 *
 * @param fraction The fraction from the starting to the ending values
 * @param startValue A 32-bit int value representing colors in the
 * separate bytes of the parameter
 * @param endValue A 32-bit int value representing colors in the
 * separate bytes of the parameter
 * @return A value that is calculated to be the linearly interpolated
 * result, derived by separating the start and end values into separate
 * color channels and interpolating each one separately, recombining the
 * resulting values in the same way.
 */
public Object evaluate(float fraction, Object startValue, Object endValue) {
    int startInt = (Integer) startValue;
    int startA = (startInt >> 24) & 0xff;
    int startR = (startInt >> 16) & 0xff;
    int startG = (startInt >> 8) & 0xff;
    int startB = startInt & 0xff;

    int endInt = (Integer) endValue;
    int endA = (endInt >> 24) & 0xff;
    int endR = (endInt >> 16) & 0xff;
    int endG = (endInt >> 8) & 0xff;
    int endB = endInt & 0xff;

    return (startA + (int)(fraction * (endA - startA))) << 24 |
            (startR + (int)(fraction * (endR - startR))) << 16 |
            (startG + (int)(fraction * (endG - startG))) << 8 |
            (startB + (int)(fraction * (endB - startB)));
}

public int getTextSelectedColor() {
    return mTextSelectedColor;
}

public void setTextSelectedColor(int textSelectedColor) {
    mTextSelectedColor = textSelectedColor;
}

public int getTextNormalColor() {
    return mTextNormalColor;
}

public void setTextNormalColor(int textNormalColor) {
    mTextNormalColor = textNormalColor;
}

public int getLastPosition() {
    return mLastPosition;
}

public void setLastPosition(int lastPosition) {
    mLastPosition = lastPosition;
}

public int getSelectedPosition() {
    return mSelectedPosition;
}

public void setSelectedPosition(int selectedPosition) {
    mSelectedPosition = selectedPosition;
}

public float getSelectionOffset() {
    return mSelectionOffset;
}

public void setSelectionOffset(float selectionOffset) {
    mSelectionOffset = selectionOffset;
}

public String[] getTitles() {
    return mTitles;
}

public void setTitles(String[] titles) {
    mTitles = titles;
}

public int[][] getIconRes() {
    return mIconRes;
}

public void setIconRes(int[][] iconRes) {
    mIconRes = iconRes;
}

public View[] getTabView() {
    return mTabView;
}

public void setTabView(View[] tabView) {
    mTabView = tabView;
}

public boolean isShowTransitionColor() {
    return mShowTransitionColor;
}

public void setShowTransitionColor(boolean showTransitionColor) {
    mShowTransitionColor = showTransitionColor;
}}

卧槽,不知不觉撸了这么多了,不过也完成了,接下来我们就直接拿着用好了。

首先我们编写一个tab_container_view:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@null">

<com.example.xjf.wxswitchdemo.TabIconView
    android:id="@+id/iv_tab_icon"
    android:layout_marginTop="3dp"
    android:layout_width="@dimen/tab_icon_width"
    android:layout_height="@dimen/tab_icon_height"
    android:layout_centerHorizontal="true"
    android:scaleType="centerInside" />

<TextView
    android:id="@+id/tv_tab_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:layout_centerHorizontal="true"
    android:layout_below="@+id/iv_tab_icon"
    android:textColor="@color/main_bottom_tab_textcolor_normal"
    /></RelativeLayout>

接下来就是activity的xml了,也比较简单,直接引用我们自定义的TabContainerView就好了

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v4.view.ViewPager
    android:id="@+id/tab_pager"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:overScrollMode="never" />

<View
    android:layout_width="match_parent"
    android:layout_height="1px"
    android:background="#999999"></View>

<com.example.xjf.wxswitchdemo.TabContainerView
    android:id="@+id/ll_tab_container"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@android:color/white" /></LinearLayout>

最后再我们的Activity中完成数据的初始化操作和简单的切换即可。

public class Activity_Two extends AppCompatActivity implements ViewPager.OnPageChangeListener{

@BindView(R.id.tab_pager)
ViewPager tabPager;
@BindView(R.id.ll_tab_container)
TabContainerView llTabContainer;

private List<Fragment> mTabs = new ArrayList<>();//Fragment集合
private MyPagerAdapter adapter;//适配器


private final int ICONS_RES[][] = {
        {
                R.mipmap.home_normal,
                R.mipmap.home_selected
        },
        {
                R.mipmap.category_normal,
                R.mipmap.category_selected
        },

        {
                R.mipmap.service_normal,
                R.mipmap.service_selected
        },
        {
                R.mipmap.mine_normal,
                R.mipmap.mine_selected
        }
};

/** tab 颜色值*/
private final int[] TAB_COLORS = new int []{
        R.color.main_bottom_tab_textcolor_normal,
        R.color.main_bottom_tab_textcolor_selected};

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

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_);
    ButterKnife.bind(this);
    initView();
}


private void initView(){

    for (int i = 0; i < mContents.length; i++) {
        TabFragment tabFragment = new TabFragment();
        Bundle bundle = new Bundle();
        bundle.putString("content", mContents[i]);
        tabFragment.setArguments(bundle);
        mTabs.add(tabFragment);
    }
    tabPager.setAdapter(adapter = new MyPagerAdapter(getSupportFragmentManager()));

    TabContainerView mTabLayout = (TabContainerView) findViewById(R.id.ll_tab_container);
    mTabLayout.setOnPageChangeListener(this);
    mTabLayout.initContainer(mContents, ICONS_RES, TAB_COLORS, true);
    int width = getResources().getDimensionPixelSize(R.dimen.tab_icon_width);
    int height = getResources().getDimensionPixelSize(R.dimen.tab_icon_height);
    mTabLayout.setContainerLayout(R.layout.tab_container_view, R.id.iv_tab_icon, R.id.tv_tab_text, width, height);
    mTabLayout.setViewPager(tabPager);
    tabPager.setCurrentItem(0);
}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {
    for (int index = 0, len = mTabs.size(); index < len; index ++) {
        mTabs.get(position).onHiddenChanged(index != position);
    }
}

@Override
public void onPageScrollStateChanged(int state) {

}

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
}

private class MyPagerAdapter extends FragmentPagerAdapter {

    //构造方法
    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }
    //返回当前Fragment
    @Override
    public Fragment getItem(int position) {
        return mTabs.get(position);
    }

    //返回Fragment个数
    @Override
    public int getCount() {
        return mTabs.size();
    }
}}
到此结束

图片资源共享一下:

mine_selected.png

service_selected.png

category_selected.png

category_normal.png

home_normal.png

home_selected.png

mine_normal.png

各位下期再见!!!!!

最后录制一张自己实现的效果图吧:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,082评论 5 464
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,231评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,047评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,977评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,893评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,976评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,605评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,888评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,906评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,732评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,513评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,980评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,132评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,447评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,027评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,232评论 2 339

推荐阅读更多精彩内容