感谢 github的作者:wuyexiong
效果图(图片和文字都有渐变效果)
实现
<br>主要用到自定义一个LinearLayout和ImageView<br><br>
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值
* 然后显示出来
* <p>
* 感谢 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)
<?xml version="1.0" encoding="utf-8"?>
<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/id_viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
<!--一定要加背景 android:background="@drawable/bg_tab_bottom"-->
<jfsl.view.view.BottomIndicator
android:id="@+id/id_bottom_indicator"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@drawable/bg_tab_bottom">
</jfsl.view.view.BottomIndicator>
</LinearLayout>
4.tab item的布局(BottomIconView+TextView)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<jfsl.view.view.BottomIconView
android:id="@+id/bottom_tab_icon"
android:layout_width="32dp"
android:layout_height="28dp"
android:layout_gravity="center_horizontal"
android:scaleType="fitCenter" />
<TextView
android:id="@+id/bottom_tab_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textSize="12sp" />
</LinearLayout>
5.Tab的背景 layer-list可以将多个图片按照顺序层叠起来
背景不能去掉,去掉之后看不到渐变的效果
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:dither="true"
android:shape="rectangle">
<solid android:color="#FFDADADA" />
</shape>
</item>
<item android:top="1px">
<shape
android:dither="true"
android:shape="rectangle">
<solid android:color="#FFFFFFFF" />
<padding android:top="1px" />
</shape>
</item>
</layer-list>
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<String> mTitles = Arrays.asList("Fragment-->微信","Fragment-->通讯录","Fragment-->发现","Fragment-->我");
private List<SimpleFragment> 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<SimpleFragment> mFragments;
public TopViewPagerAdapter(FragmentManager fm,Context context,List<SimpleFragment> 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;
}
}
代码地址 http://114.215.171.206/14551100130/android_view/bottomtab.zip
图标素材( 放在xxhdpi)
热门评论
挺不错的一个分享,虽说我没有学过android开发,不过还是有学习借鉴意义的。
之前有基于html5+css3开发的仿微信聊天项目|仿微信语音效果,也是挺不错的一个项目。
addOnPageChangeListener和getSupportFragmentManager()报错,什么原因呢 求博主回复一下