自定義通用的底部Tab切換導航欄(四)

通用的底部導航欄

可自主設置底部導航欄的消息數(shù)及提醒

用CV大法即可

都說“所有貼代碼不貼效果圖的都是耍流氓”,效果圖獻上


效果圖.jpg

下載鏈接:https://share.weiyun.com/5WwrtkH

public class MainActivity extends AppCompatActivity {

    private ViewPager mVpContent;
    private BottomBarLayout mBottomBarLayout;

    private List<TabFragment> mFragmentList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
        initListener();
    }
    private void initView() {
        mVpContent = (ViewPager) findViewById(R.id.vp_content);
        mBottomBarLayout = (BottomBarLayout) findViewById(R.id.bbl);
    }

    private void initData() {

        TabFragment homeFragment = new TabFragment();
        Bundle bundle1 = new Bundle();
        bundle1.putString(TabFragment.CONTENT,"第一個頁面");
        homeFragment.setArguments(bundle1);
        mFragmentList.add(homeFragment);

        TabFragment videoFragment = new TabFragment();
        Bundle bundle2 = new Bundle();
        bundle2.putString(TabFragment.CONTENT,"第二個頁面");
        videoFragment.setArguments(bundle2);
        mFragmentList.add(videoFragment);

        TabFragment microFragment = new TabFragment();
        Bundle bundle3 = new Bundle();
        bundle3.putString(TabFragment.CONTENT,"第三個頁面");
        microFragment.setArguments(bundle3);
        mFragmentList.add(microFragment);

        TabFragment meFragment = new TabFragment();
        Bundle bundle4 = new Bundle();
        bundle4.putString(TabFragment.CONTENT,"第四個頁面");
        meFragment.setArguments(bundle4);
        mFragmentList.add(meFragment);
    }

    private void initListener() {
        mVpContent.setAdapter(new MyAdapter(getSupportFragmentManager(),mFragmentList));
        mBottomBarLayout.setViewPager(mVpContent);

        mBottomBarLayout.setUnread(0,20);//設置第一個頁簽的未讀數(shù)為20
        mBottomBarLayout.setUnread(1,101);//設置第二個頁簽的未讀數(shù)
        mBottomBarLayout.showNotify(2);//設置第三個頁簽顯示提示的小紅點
        mBottomBarLayout.setMsg(3,"NEW");//設置第四個頁簽顯示NEW提示文字
    }
}
class MyAdapter extends FragmentStatePagerAdapter {

    private List<TabFragment> mFragmentList;

    public MyAdapter(FragmentManager fm, List<TabFragment> fragmentList) {
        super(fm);
        this.mFragmentList = fragmentList;
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }
}
public class TabFragment extends Fragment {

    public static final String CONTENT = "content";
    private TextView mTextView;


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle bundle) {
        mTextView = new TextView(getActivity());
        mTextView.setGravity(Gravity.CENTER);
        String content = getArguments().getString(CONTENT);
        mTextView.setText(content);
        return mTextView;
    }
}
public class BottomBarItem extends LinearLayout {

    private Context mContext;
    private int     mIconNormalResourceId;//普通狀態(tài)圖標的資源id
    private int     mIconSelectedResourceId;//選中狀態(tài)圖標的資源id
    private String  mText;//文本
    private int mTextSize = 12;//文字大小 默認為12sp
    private int mTextColorNormal = 0xFF999999;    //描述文本的默認顯示顏色
    private int mTextColorSelected = 0xFF46C01B;  //述文本的默認選中顯示顏色
    private int mWhiteColor = 0xFFFFFFFF;  //白色
    private int mMarginTop = 0;//文字和圖標的距離,默認0dp
    private boolean mOpenTouchBg = false;// 是否開啟觸摸背景,默認關閉
    private Drawable mTouchDrawable;//觸摸時的背景
    private int      mIconWidth;//圖標的寬度
    private int      mIconHeight;//圖標的高度
    private int      mItemPadding;//BottomBarItem的padding


    private ImageView mImageView;
    private TextView  mTvUnread;
    private TextView  mTvNotify;
    private TextView  mTvMsg;
    private TextView  mTextView;

    private int mUnreadTextSize = 10; //未讀數(shù)默認字體大小10sp
    private int mMsgTextSize = 6; //消息默認字體大小6sp
    private int unreadNumThreshold = 99;//未讀數(shù)閾值
    private int      mUnreadTextColor;//未讀數(shù)字體顏色
    private Drawable mUnreadTextBg;
    private int      mMsgTextColor;
    private Drawable mMsgTextBg;
    private Drawable mNotifyPointBg;

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

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

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

        mContext = context;

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BottomBarItem);

        initAttrs(ta); //初始化屬性

        ta.recycle();

        checkValues();//檢查值是否合法

        init();//初始化相關操作
    }

    private void initAttrs(TypedArray ta) {
        mIconNormalResourceId = ta.getResourceId(R.styleable.BottomBarItem_iconNormal, -1);
        mIconSelectedResourceId = ta.getResourceId(R.styleable.BottomBarItem_iconSelected, -1);

        mText = ta.getString(R.styleable.BottomBarItem_itemText);
        mTextSize = ta.getDimensionPixelSize(R.styleable.BottomBarItem_itemTextSize, UIUtils.sp2px(mContext, mTextSize));

        mTextColorNormal = ta.getColor(R.styleable.BottomBarItem_textColorNormal, mTextColorNormal);
        mTextColorSelected = ta.getColor(R.styleable.BottomBarItem_textColorSelected, mTextColorSelected);

        mMarginTop = ta.getDimensionPixelSize(R.styleable.BottomBarItem_itemMarginTop, UIUtils.dip2Px(mContext, mMarginTop));

        mOpenTouchBg = ta.getBoolean(R.styleable.BottomBarItem_openTouchBg, mOpenTouchBg);
        mTouchDrawable = ta.getDrawable(R.styleable.BottomBarItem_touchDrawable);

        mIconWidth = ta.getDimensionPixelSize(R.styleable.BottomBarItem_iconWidth, 0);
        mIconHeight = ta.getDimensionPixelSize(R.styleable.BottomBarItem_iconHeight, 0);
        mItemPadding = ta.getDimensionPixelSize(R.styleable.BottomBarItem_itemPadding, 0);

        mUnreadTextSize = ta.getDimensionPixelSize(R.styleable.BottomBarItem_unreadTextSize, UIUtils.sp2px(mContext, mUnreadTextSize));
        mUnreadTextColor = ta.getColor(R.styleable.BottomBarItem_unreadTextColor, 0xFFFFFFFF);
        mUnreadTextBg = ta.getDrawable(R.styleable.BottomBarItem_unreadTextBg);

        mMsgTextSize = ta.getDimensionPixelSize(R.styleable.BottomBarItem_msgTextSize, UIUtils.sp2px(mContext, mMsgTextSize));
        mMsgTextColor = ta.getColor(R.styleable.BottomBarItem_msgTextColor, 0xFFFFFFFF);
        mMsgTextBg = ta.getDrawable(R.styleable.BottomBarItem_msgTextBg);

        mNotifyPointBg = ta.getDrawable(R.styleable.BottomBarItem_notifyPointBg);

        unreadNumThreshold = ta.getInteger(R.styleable.BottomBarItem_unreadThreshold,99);
    }

    /**
     * 檢查傳入的值是否完善
     */
    private void checkValues() {
        if (mIconNormalResourceId == -1) {
            throw new IllegalStateException("您還沒有設置默認狀態(tài)下的圖標辩块,請指定iconNormal的圖標");
        }

        if (mIconSelectedResourceId == -1) {
            throw new IllegalStateException("您還沒有設置選中狀態(tài)下的圖標荆永,請指定iconSelected的圖標");
        }

        if (mOpenTouchBg && mTouchDrawable == null) {
            //如果有開啟觸摸背景效果但是沒有傳對應的drawable
            throw new IllegalStateException("開啟了觸摸效果废亭,但是沒有指定touchDrawable");
        }

        if (mUnreadTextBg == null){
            mUnreadTextBg = getResources().getDrawable(R.drawable.shape_unread);
        }

        if (mMsgTextBg == null){
            mMsgTextBg = getResources().getDrawable(R.drawable.shape_msg);
        }

        if (mNotifyPointBg == null){
            mNotifyPointBg = getResources().getDrawable(R.drawable.shape_notify_point);
        }
    }

    private void init() {
        setOrientation(VERTICAL);
        setGravity(Gravity.CENTER);

        View view = initView();

        mImageView.setImageResource(mIconNormalResourceId);

        if (mIconWidth != 0 && mIconHeight != 0) {
            //如果有設置圖標的寬度和高度具钥,則設置ImageView的寬高
            FrameLayout.LayoutParams imageLayoutParams = (FrameLayout.LayoutParams) mImageView.getLayoutParams();
            imageLayoutParams.width = mIconWidth;
            imageLayoutParams.height = mIconHeight;
            mImageView.setLayoutParams(imageLayoutParams);
        }

        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);//設置底部文字字體大小

        mTvUnread.setTextSize(TypedValue.COMPLEX_UNIT_PX, mUnreadTextSize);//設置未讀數(shù)的字體大小
        mTvUnread.setTextColor(mUnreadTextColor);//設置未讀數(shù)字體顏色
        mTvUnread.setBackground(mUnreadTextBg);//設置未讀數(shù)背景

        mTvMsg.setTextSize(TypedValue.COMPLEX_UNIT_PX, mMsgTextSize);//設置提示文字的字體大小
        mTvMsg.setTextColor(mMsgTextColor);//設置提示文字的字體顏色
        mTvMsg.setBackground(mMsgTextBg);//設置提示文字的背景顏色

        mTvNotify.setBackground(mNotifyPointBg);//設置提示點的背景顏色

        mTextView.setTextColor(mTextColorNormal);//設置底部文字字體顏色
        mTextView.setText(mText);//設置標簽文字

        LayoutParams textLayoutParams = (LayoutParams) mTextView.getLayoutParams();
        textLayoutParams.topMargin = mMarginTop;
        mTextView.setLayoutParams(textLayoutParams);

        if (mOpenTouchBg) {
            //如果有開啟觸摸背景
            setBackground(mTouchDrawable);
        }

        addView(view);
    }

    @NonNull
    private View initView() {
        View view = View.inflate(mContext, R.layout.item_bottom_bar, null);
        if (mItemPadding != 0) {
            //如果有設置item的padding
            view.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
        }
        mImageView = (ImageView) view.findViewById(R.id.iv_icon);
        mTvUnread = (TextView) view.findViewById(R.id.tv_unred_num);
        mTvMsg = (TextView) view.findViewById(R.id.tv_msg);
        mTvNotify = (TextView) view.findViewById(R.id.tv_point);
        mTextView = (TextView) view.findViewById(R.id.tv_text);
        return view;
    }

    public ImageView getImageView() {
        return mImageView;
    }

    public TextView getTextView() {
        return mTextView;
    }

    public void setIconNormalResourceId(int mIconNormalResourceId) {
        this.mIconNormalResourceId = mIconNormalResourceId;
    }

    public void setIconSelectedResourceId(int mIconSelectedResourceId) {
        this.mIconSelectedResourceId = mIconSelectedResourceId;
    }

    public void setStatus(boolean isSelected) {
        mImageView.setImageDrawable(getResources().getDrawable(isSelected ? mIconSelectedResourceId : mIconNormalResourceId));
        mTextView.setTextColor(isSelected ? mTextColorSelected : mTextColorNormal);
    }

    private void setTvVisiable(TextView tv) {
        //都設置為不可見
        mTvUnread.setVisibility(GONE);
        mTvMsg.setVisibility(GONE);
        mTvNotify.setVisibility(GONE);

        tv.setVisibility(VISIBLE);//設置為可見
    }

    public int getUnreadNumThreshold() {
        return unreadNumThreshold;
    }

    public void setUnreadNumThreshold(int unreadNumThreshold) {
        this.unreadNumThreshold = unreadNumThreshold;
    }

    /**
     * 設置未讀數(shù)
     *
     * @param unreadNum 小于等于{@link #unreadNumThreshold}則隱藏桃漾,
     *                  大于0小于{@link #unreadNumThreshold}則顯示對應數(shù)字,
     *                  超過{@link #unreadNumThreshold}
     *                  顯示{@link #unreadNumThreshold}+
     */
    public void setUnreadNum(int unreadNum) {
        setTvVisiable(mTvUnread);
        if (unreadNum <= 0) {
            mTvUnread.setVisibility(GONE);
        } else if (unreadNum <= unreadNumThreshold) {
            mTvUnread.setText(String.valueOf(unreadNum));
        } else {
            mTvUnread.setText(String.format(Locale.CHINA, "%d+", unreadNumThreshold));
        }
    }

    public void setMsg(String msg) {
        setTvVisiable(mTvMsg);
        mTvMsg.setText(msg);
    }

    public void hideMsg() {
        mTvMsg.setVisibility(GONE);
    }

    public void showNotify() {
        setTvVisiable(mTvNotify);
    }

    public void hideNotify() {
        mTvNotify.setVisibility(GONE);
    }
}
public class BottomBarLayout extends LinearLayout implements ViewPager.OnPageChangeListener {

    private static final String STATE_INSTANCE = "instance_state";
    private static final String STATE_ITEM     = "state_item";


    private ViewPager mViewPager;
    private int       mChildCount;//子條目個數(shù)
    private List<BottomBarItem> mItemViews = new ArrayList<>();
    private int mCurrentItem;//當前條目的索引
    private boolean mSmoothScroll;

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

    public BottomBarLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BottomBarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BottomBarLayout);
        mSmoothScroll = ta.getBoolean(R.styleable.BottomBarLayout_smoothScroll,false);
        ta.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init();
    }

    @Override
    public void setOrientation(int orientation) {
        super.setOrientation(orientation);
    }

    public void setViewPager(ViewPager viewPager) {
        this.mViewPager = viewPager;
        init();
    }

    private void init() {
        mChildCount = getChildCount();

        if (mViewPager != null) {
            if (mViewPager.getAdapter().getCount() != mChildCount) {
                throw new IllegalArgumentException("LinearLayout的子View數(shù)量必須和ViewPager條目數(shù)量一致");
            }
        }

        for (int i = 0; i < mChildCount; i++) {
            if (getChildAt(i) instanceof BottomBarItem) {
                BottomBarItem bottomBarItem = (BottomBarItem) getChildAt(i);
                mItemViews.add(bottomBarItem);
                //設置點擊監(jiān)聽
                bottomBarItem.setOnClickListener(new MyOnClickListener(i));
            } else {
                throw new IllegalArgumentException("BottomBarLayout的子View必須是BottomBarItem");
            }
        }

        mItemViews.get(mCurrentItem).setStatus(true);//設置選中項

        if (mViewPager != null){
            mViewPager.setOnPageChangeListener(this);
        }
    }

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

    }

    @Override
    public void onPageSelected(int position) {
        resetState();
        mItemViews.get(position).setStatus(true);
        if (onItemSelectedListener != null){
            onItemSelectedListener.onItemSelected(getBottomItem(position),mCurrentItem,position);
        }
        mCurrentItem = position;//記錄當前位置
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    private class MyOnClickListener implements OnClickListener {

        private int currentIndex;

        public MyOnClickListener(int i) {
            this.currentIndex = i;
        }

        @Override
        public void onClick(View v) {
            //回調點擊的位置
            if(mViewPager != null){
                //有設置viewPager
                if (currentIndex == mCurrentItem){
                    //如果還是同個頁簽敦迄,使用setCurrentItem不會回調OnPageSelecte(),所以在此處需要回調點擊監(jiān)聽
                    if (onItemSelectedListener != null) {
                        onItemSelectedListener.onItemSelected(getBottomItem(currentIndex),mCurrentItem,currentIndex);
                    }
                }else{
                    mViewPager.setCurrentItem(currentIndex, mSmoothScroll);
                }
            }else{
                //沒有設置viewPager
                if (onItemSelectedListener != null) {
                    onItemSelectedListener.onItemSelected(getBottomItem(currentIndex),mCurrentItem,currentIndex);
                }

                updateTabState(currentIndex);
            }
        }
    }

    private void updateTabState(int position){
        resetState();
        mCurrentItem = position;
        mItemViews.get(mCurrentItem).setStatus(true);
    }

    /**
     * 重置當前按鈕的狀態(tài)
     */
    private void resetState() {
        if (mCurrentItem < mItemViews.size()){
            mItemViews.get(mCurrentItem).setStatus(false);
        }
    }

    public void setCurrentItem(int currentItem) {
        if (mViewPager != null){
            mViewPager.setCurrentItem(currentItem,mSmoothScroll);
        }else{
            updateTabState(currentItem);
        }
    }

    /**
     * 設置未讀數(shù)
     * @param position 底部標簽的下標
     * @param unreadNum 未讀數(shù)
     */
    public void setUnread(int position,int unreadNum){
        mItemViews.get(position).setUnreadNum(unreadNum);
    }

    /**
     * 設置提示消息
     * @param position 底部標簽的下標
     * @param msg 未讀數(shù)
     */
    public void setMsg(int position,String msg){
        mItemViews.get(position).setMsg(msg);
    }

    /**
     * 隱藏提示消息
     * @param position 底部標簽的下標
     */
    public void hideMsg(int position){
        mItemViews.get(position).hideMsg();
    }

    /**
     * 顯示提示的小紅點
     * @param position 底部標簽的下標
     */
    public void showNotify(int position){
        mItemViews.get(position).showNotify();
    }

    /**
     * 隱藏提示的小紅點
     * @param position 底部標簽的下標
     */
    public void hideNotify(int position){
        mItemViews.get(position).hideNotify();
    }

    public int getCurrentItem() {
        return mCurrentItem;
    }

    public void setSmoothScroll(boolean smoothScroll) {
        this.mSmoothScroll = smoothScroll;
    }

    public BottomBarItem getBottomItem(int position){
        return mItemViews.get(position);
    }

    /**
     * @return 當View被銷毀的時候恋追,保存數(shù)據(jù)
     */
    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());
        bundle.putInt(STATE_ITEM, mCurrentItem);
        return bundle;
    }

    /**
     * @param state 用于恢復數(shù)據(jù)使用
     */
    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            mCurrentItem = bundle.getInt(STATE_ITEM);
            //重置所有按鈕狀態(tài)
            resetState();
            //恢復點擊的條目顏色
            mItemViews.get(mCurrentItem).setStatus(true);
            super.onRestoreInstanceState(bundle.getParcelable(STATE_INSTANCE));
        } else {
            super.onRestoreInstanceState(state);
        }
    }

    private OnItemSelectedListener onItemSelectedListener;

    public interface OnItemSelectedListener {
        void onItemSelected(BottomBarItem bottomBarItem, int previousPosition, int currentPosition);
    }

    public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
        this.onItemSelectedListener = onItemSelectedListener;
    }
}
public class UIUtils {
    /**
     * dip-->px
     */
    public static int dip2Px(Context context, int dip) {
        // px/dip = density;
        // density = dpi/160
        // 320*480 density = 1 1px = 1dp
        // 1280*720 density = 2 2px = 1dp

        float density = context.getResources().getDisplayMetrics().density;
        int px = (int) (dip * density + 0.5f);
        return px;
    }

    /**
     * 將sp值轉換為px值,保證文字大小不變
     *
     * @param spValue
     * @return
     */
    public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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/vp_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        ></android.support.v4.view.ViewPager>

    <com.clkj.bottombar.bottombar.BottomBarLayout
        android:id="@+id/bbl"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:orientation="horizontal"
        android:gravity="center"
        android:layout_gravity="center"
        android:background="@color/tab_gb"
        >

        <com.clkj.bottombar.bottombar.BottomBarItem
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            app:iconNormal="@mipmap/tab_home_normal"
            app:iconSelected="@mipmap/tab_home_selected"
            app:itemText="首頁"
            app:textColorNormal="@color/tab_normal_color"
            app:textColorSelected="@color/tab_selected_color"
            app:itemTextSize="8sp"
            app:itemMarginTop="-5dp"
            app:openTouchBg="true"
            app:touchDrawable="@drawable/selector_bg"
            />

        <com.clkj.bottombar.bottombar.BottomBarItem
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            app:iconNormal="@mipmap/tab_video_normal"
            app:iconSelected="@mipmap/tab_video_selected"
            app:itemText="視頻"
            app:textColorNormal="@color/tab_normal_color"
            app:textColorSelected="@color/tab_selected_color"
            app:itemTextSize="8sp"
            app:itemMarginTop="-5dp"
            app:openTouchBg="true"
            app:unreadThreshold="99"
            app:touchDrawable="@drawable/selector_bg"
            />


        <com.clkj.bottombar.bottombar.BottomBarItem
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            app:iconNormal="@mipmap/tab_micro_normal"
            app:iconSelected="@mipmap/tab_micro_selected"
            app:itemText="微頭條"
            app:textColorNormal="@color/tab_normal_color"
            app:textColorSelected="@color/tab_selected_color"
            app:itemTextSize="8sp"
            app:itemMarginTop="-5dp"
            app:openTouchBg="true"
            app:touchDrawable="@drawable/selector_bg"
            />

        <com.clkj.bottombar.bottombar.BottomBarItem
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            app:iconNormal="@mipmap/tab_me_normal"
            app:iconSelected="@mipmap/tab_me_selected"
            app:itemText="我的"
            app:textColorNormal="@color/tab_normal_color"
            app:textColorSelected="@color/tab_selected_color"
            app:itemTextSize="8sp"
            app:itemMarginTop="-5dp"
            app:openTouchBg="true"
            app:touchDrawable="@drawable/selector_bg"
            />

    </com.clkj.bottombar.bottombar.BottomBarLayout>
</LinearLayout>

item_bottom_bar.xml

<?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="wrap_content"
              android:layout_gravity="center"
              android:gravity="center"
              android:orientation="vertical"
    >


    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            />

        <TextView
            android:id="@+id/tv_unred_num"
            android:layout_width="wrap_content"
            android:minWidth="15dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginLeft="14dp"
            android:background="@drawable/shape_unread"
            android:gravity="center"
            android:text="99+"
            android:textColor="@color/white"
            android:textSize="10sp"
            android:visibility="gone" />

        <TextView
            android:id="@+id/tv_msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginLeft="14dp"
            android:background="@drawable/shape_msg"
            android:gravity="center"
            android:text="NEW"
            android:textColor="@color/white"
            android:textSize="6sp"
            android:visibility="gone" />

        <TextView
            android:id="@+id/tv_point"
            android:layout_width="10dp"
            android:layout_height="10dp"
            android:layout_gravity="center_horizontal"
            android:layout_marginLeft="10dp"
            android:background="@drawable/shape_notify_point"
            android:gravity="center"
            android:textSize="6sp"
            android:visibility="gone" />

    </FrameLayout>


    <TextView
        android:id="@+id/tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</LinearLayout>

attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="BottomBarItem">
        <!--默認狀態(tài)下的圖標-->
        <attr name="iconNormal" format="reference"/>
        <!--選中狀態(tài)下的圖標-->
        <attr name="iconSelected" format="reference"/>

        <!--底部文字-->
        <attr name="itemText" format="string"/>
        <!--文字大小-->
        <attr name="itemTextSize" format="dimension"/>
        <!--默認狀態(tài)下的文字顏色-->
        <attr name="textColorNormal" format="color"/>
        <!--選中狀態(tài)下的文字顏色-->
        <attr name="textColorSelected" format="color"/>

        <!--文字和圖標的頂部距離-->
        <attr name="itemMarginTop" format="dimension"/>

        <!--是否開啟觸摸背景效果-->
        <attr name="openTouchBg" format="boolean"/>
        <!--設置觸摸背景-->
        <attr name="touchDrawable" format="reference"/>

        <!--設置圖標的寬度-->
        <attr name="iconWidth" format="dimension"/>
        <!--設置圖標的高度-->
        <attr name="iconHeight" format="dimension"/>

        <!--設置BottomBarItem的padding-->
        <attr name="itemPadding" format="dimension"/>

        <!--設置未讀數(shù)字體大小-->
        <attr name="unreadTextSize" format="dimension"/>
        <!--設置未讀數(shù)字體顏色-->
        <attr name="unreadTextColor" format="reference"/>
        <!--設置未讀數(shù)背景色-->
        <attr name="unreadTextBg" format="reference"/>

        <!--設置提示消息字體大小-->
        <attr name="msgTextSize" format="dimension"/>
        <!--設置提示消息字體顏色-->
        <attr name="msgTextColor" format="reference"/>
        <!--設置提示消息背景-->
        <attr name="msgTextBg" format="reference"/>

        <!--設置提示點背景-->
        <attr name="notifyPointBg" format="reference"/>

        <!--設置未讀數(shù)組閾值 大于閾值的數(shù)字將顯示為 n+ n為設置的閾值-->
        <attr name="unreadThreshold" format="integer"/>
    </declare-styleable>

    <declare-styleable name="BottomBarLayout">
        <attr name="smoothScroll" format="boolean"/>
    </declare-styleable>
</resources>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>



    <color name="tab_gb">#F3F5F4</color>
    <color name="tab_normal_color">#515051</color>
    <color name="tab_selected_color">#D33D3C</color>

    <color name="unreadTextColor">#00ff00</color>
    <color name="msgTextColor">#00ff00</color>

    <color name="red">#ff0000</color>
    <color name="selector_grey">#DDDDDD</color>
    <color name="white">#FFFFFF</color>
</resources>
tab_home_normal.png
tab_home_selected.png
tab_me_normal.png
tab_me_selected.png
tab_micro_normal.png
tab_micro_selected.png
tab_video_normal.png
tab_video_selected.png

當需要禁止viewpager滑動時

/**
 * 可以控制滑動的ViewPager
 */
public class MyViewPager extends ViewPager {
    private boolean mIsCanScroll = false;

    public MyViewPager(Context context) {
        super(context);
    }

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

    public boolean onTouchEvent(MotionEvent event) {
        if (this.mIsCanScroll) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (this.mIsCanScroll) {
            return super.onInterceptTouchEvent(event);
        }

        return false;
    }

    public void setCanScroll(boolean isCanScroll) {
        this.mIsCanScroll = isCanScroll;
    }

    @Override
    public void setCurrentItem(int item) {
        super.setCurrentItem(item, false);
    }
}

在MainActivity設置mVpContent.setCanScroll(false);即可
別忘了ViewPager將強轉成MyViewPager

新增常用的方法:

點擊返回提示 “再按一次退出程序” 罚屋,2秒內在按一次苦囱,退出APP

/**
 * 管理activity stack
 */
public class AppManager {

    private static Stack<Activity> mActivityStack;
    //存放Class信息Map
    private static Map<String,Class<?>> mClassMap = new HashMap<>();

    public AppManager() {
    }

    /**
     * 單一實例
     */
    public static AppManager getInstance() {
        return SingleApp.INSTANCE;
    }

    public static class SingleApp {
        public static AppManager INSTANCE = new AppManager();
    }

    /**
     * 獲取map中的Class
     * @param className
     * @return
     */
    public Class<?> getClassFromMap(String className){
        return mClassMap.get(className);
    }

    /**
     * 添加Activity到堆棧
     */
    public void addActivity(Activity activity) {
        if (mActivityStack == null) {
            mActivityStack = new Stack<Activity>();
        }
        mActivityStack.add(activity);
        //加入到map
        mClassMap.put(activity.getClass().getSimpleName(),activity.getClass());
    }

    /**
     * 移除Activity
     */
    public void removeActivity(Activity activity) {
        mActivityStack.remove(activity);
        //從map中移除
        mClassMap.remove(activity.getClass().getSimpleName());
    }

    /**
     * 獲取指定的Activity
     */
    public Activity getActivity(Class<?> cls) {
        if (mActivityStack != null)
            for (Activity activity : mActivityStack) {
                if (activity.getClass().equals(cls)) {
                    return activity;
                }
            }
        return null;
    }

    /**
     * 獲取當前顯示Activity(堆棧中最后一個傳入的activity)
     */
    public Activity getLastActivity() {
        Activity activity = mActivityStack.lastElement();
        return activity;
    }

    /**
     * 獲取所有Activity
     */
    public Stack<Activity> getAllActivityStacks() {
        return mActivityStack;
    }

    /**
     * 結束指定的Activity
     */
    public void finishActivity(Activity activity) {
        if (activity != null) {
            if (!activity.isFinishing()) {
                activity.finish();
                mActivityStack.remove(activity);
            }
        }
    }

    /**
     * 結束指定類名的Activity
     */
    public void finishActivity(Class<?> cls) {
        for (Activity activity : mActivityStack) {
            if (activity.getClass().equals(cls)) {
                finishActivity(activity);
                break;
            }
        }
    }

    /**
     * 結束除當前傳入以外所有Activity
     */
    public void finishOthersActivity(Class<?> cls) {
        if (mActivityStack != null)
            for (Activity activity : mActivityStack) {
                if (!activity.getClass().equals(cls)) {
                    activity.finish();
                }
            }
    }

    /**
     * 結束所有Activity
     */
    public void finishAllActivity() {
        if (mActivityStack != null)
            for (Activity activity : mActivityStack) {
                activity.finish();
            }
        mActivityStack.clear();
    }


    /**
     * 退出應用程序
     */
    public void AppExit() {
        try {
            finishAllActivity();
            android.os.Process.killProcess(android.os.Process.myPid());// 殺死該應用進程
            System.exit(0);
        } catch (Exception e) {
        }
    }
}

在MainActivity中入棧
AppManager.getInstance().addActivity(this);
然后復寫方法

/**
     * 退出程序邏輯
     *
     * @param keyCode
     * @param event
     * @return
     */
    private long lastBackTime = 0;
    private static final long TIME_INTERVAL = 2 * 1000;
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
            long currentBackTime = System.currentTimeMillis();
            Toast.makeText(MainActivity.this,"再按一次退出程序",Toast.LENGTH_SHORT).show();
            //雙擊退出程序
            if (currentBackTime - lastBackTime > TIME_INTERVAL) {
                lastBackTime = currentBackTime;
            } else {
                //退出
                AppManager.getInstance().AppExit();
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市脾猛,隨后出現(xiàn)的幾起案子撕彤,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羹铅,死亡現(xiàn)場離奇詭異蚀狰,居然都是意外死亡,警方通過查閱死者的電腦和手機职员,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門麻蹋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人焊切,你說我怎么就攤上這事扮授。” “怎么了专肪?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵刹勃,是天一觀的道長。 經(jīng)常有香客問我牵祟,道長深夯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任诺苹,我火速辦了婚禮咕晋,結果婚禮上,老公的妹妹穿的比我還像新娘收奔。我一直安慰自己击奶,他們只是感情好希太,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般侥加。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹲诀,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天岸晦,我揣著相機與錄音,去河邊找鬼念祭。 笑死兑宇,一個胖子當著我的面吹牛,可吹牛的內容都是我干的粱坤。 我是一名探鬼主播隶糕,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼站玄!你這毒婦竟也來了枚驻?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤株旷,失蹤者是張志新(化名)和其女友劉穎再登,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡霎冯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年铃拇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沈撞。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡慷荔,死狀恐怖,靈堂內的尸體忽然破棺而出缠俺,到底是詐尸還是另有隱情显晶,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布壹士,位于F島的核電站磷雇,受9級特大地震影響,放射性物質發(fā)生泄漏躏救。R本人自食惡果不足惜唯笙,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盒使。 院中可真熱鬧崩掘,春花似錦、人聲如沸少办。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽英妓。三九已至挽放,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蔓纠,已是汗流浹背辑畦。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留腿倚,地道東北人航闺。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像猴誊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子侮措,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,085評論 25 707
  • 用兩張圖告訴你懈叹,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,714評論 2 59
  • 1分扎、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,979評論 3 119
  • 舊時孩提總愚癡澄成,心中欲念各不同。 如今長大十七歲,回首往事已成空墨状。
    愿得一段佳話常人點頭閱讀 259評論 0 3
  • 一時興起卫漫,只代表個人觀點,不喜勿觀肾砂。 現(xiàn)如今社會列赎,藝人就好比市場的白菜一般,隨處可見镐确,層出不窮包吝。你可能今天喜歡這個...
    Vicky樂園閱讀 199評論 0 0