前言
项目需要做一个选项卡的功能,很简单,就是点击切换的效果,公共有这个控件,但是不太符合业务需求,所以自己花了半小时写了一个,很简单,继承自linearLayout,支持预置选择哪个选项卡,支持显示红点,支持选择回调。
项目很简单,一直在纠结要不要写博客,最后为了坚持还是写了,毕竟万变不离其宗,复杂的效果也是简单的逻辑一个个堆砌起来的。写一下,希望也能帮助一些初学者
效果图
照例,我们先看效果图有一个整体的认识
可以看到效果还是不错的,不过不支持横向滑动,你可以自己在外层嵌套一个横向滚动的scrollview来实现,或者更高级的自己去实现可横向滑动的tab。
怎么实现
这个demo也可以说是自定义控件的入门。
我们自己定义一个类TabLayout继承自LinearLayout,很开心的是我们并不需要重写OnLayout或者onMeasure方法,只需要根据我们的逻辑自己去实现就行了,只要你能够很顺畅的将这个Demo写完,我相信OnLayout onMeasure也不在话下,因为我们都是遍历子view进行相应的逻辑运算的。
继承控件LinearLayout,并在默认构造方法中去初始化一些参数
public class TabLayout extends LinearLayout {
private Context mContext;
private LayoutInflater mInflater;
private String[] mTitles;
private OnTabSelectListener mListener;//点击回调
private SparseArray<View> mTitleViews;//保存一下我们的textView;
private SparseArray<View> mLineViews;//保存一下我们的下划线
public TabLayout(Context context) {
this(context, null);
}
public TabLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
mInflater = LayoutInflater.from(context);
mTitleViews = new SparseArray<>();
mLineViews = new SparseArray<>();
this.setOrientation(HORIZONTAL);
this.setGravity(Gravity.CENTER_HORIZONTAL);
}
给外部提供接口好让用户和使用listview等控件一样去使用
public void setTabSelectListener(OnTabSelectListener listener) {
mListener = listener;
}
public void setData(String[] titles) {
mTitles = titles;
layoutViews();
}
核心逻辑layoutViews()
private void layoutViews() {
if (mTitles != null && mTitles.length != 0) {
for (int i = 0; i < mTitles.length; i++) {
final View childView = mInflater.inflate(R.layout.tab_layout_item, this, false);
final TextView titleView = (TextView) childView.findViewById(R.id.hotel_tab_tv_title);
TextView tvLine = (TextView) childView.findViewById(R.id.tv_line);
if (i == 0) {//默认第一个高亮
titleView.setTextColor(mContext.getResources().getColor(R.color.main_green));
tvLine.setVisibility(VISIBLE);
}
titleView.setText(mTitles[i]);
this.addView(childView);
final int position = i;
childView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onTabSelect(position);
setTabTitleColor(position);//刷新view状态
}
}
});
mTitleViews.put(i, titleView);
mLineViews.put(i, tvLine);
}
}
}
在这段逻辑中我们需要根据外部传来的数据源进行view的赋值 ,遍历外部数据源,根据外部数据源的数量生成等量的子view并将其添加进当前父view中,为了避免重复的findViewById,我们将我们需要的view添加进sparesArray中,以后面再次使用。
接下来就是提供外部接口去控制一些view的显示功能
很简单
//控制哪个tab高亮
public void setTabSelect(int position) {
setTabTitleColor(position);
if (mListener != null) {
mListener.onTabSelect(position);
}
}
//控制红点显示
public void setRedPointVisible(int position) {
View childView = this.getChildAt(position);
View billView = childView.findViewById(R.id.hotel_tab_tv_first_bill);
billView.setVisibility(VISIBLE);
}
//控制红点的隐藏
public void setRedPointGone(int position) {
View childView = this.getChildAt(position);
View billView = childView.findViewById(R.id.hotel_tab_tv_first_bill);
billView.setVisibility(GONE);
}
就是这样,代码还是很简单的,权当一次记录学习
主代码调用方式如下
package com.lyd.tablayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
import view.TabLayout;
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
String[] mTitles = new String[]{"流行音乐", "经典音乐", "轻音乐"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
mTabLayout.setData(mTitles);
mTabLayout.setRedPointVisible(0);
mTabLayout.setTabSelectListener(new TabLayout.OnTabSelectListener() {
@Override
public void onTabSelect(int position) {
Toast.makeText(MainActivity.this, position + "", Toast.LENGTH_SHORT).show();
}
});
}
}
代码已经上传到github
https://github.com/nbwzlyd/TabLayoutDemo
欢迎下载star