先看效果图:
下面三个TAB,第一个消息TAB上面又有两个TAB,很显然下面是三个Fragment,这里推荐两篇文章,关于TAB主界面必看:
郭霖:Android Fragment应用实战,使用碎片向ActivityGroup说再见
鸿洋:Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager
MainActivity布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp">
</FrameLayout>
<include
layout="@layout/bottom"/>
</LinearLayout>
FrameLayout 加载fragment,bottom 就是底部栏,如下:
<?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="50dp"
android:background="#ffffffff"
android:orientation="vertical"
>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#FFDEDEDE" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<LinearLayout
android:id="@+id/message_layout"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:orientation="vertical" >
<ImageView
android:id="@+id/message_image"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/msg_img_selector"
/>
<TextView
android:id="@+id/message_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:text="消息"
android:textColor="#82858b" />
</LinearLayout>
<LinearLayout
android:id="@+id/contacts_layout"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_centerVertical="true"
android:layout_weight="1"
android:orientation="vertical" >
<ImageView
android:id="@+id/contacts_image"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="center_horizontal"
android:src="@drawable/contact_img_selector" />
<TextView
android:id="@+id/contacts_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="联系人"
android:textColor="#82858b" />
</LinearLayout>
<LinearLayout
android:id="@+id/news_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_centerVertical="true"
android:orientation="vertical" >
<ImageView
android:id="@+id/news_image"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="center_horizontal"
android:src="@drawable/news_img_selector" />
<TextView
android:id="@+id/news_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="动态"
android:textColor="#82858b" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
并附上相应的图片selector:
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 默认时的背景图片-->
<!-- 没有焦点时的背景图片 -->
<!-- 非触摸模式下获得焦点并单击时的背景图片 -->
<item android:state_focused="true" android:state_pressed="true" android:drawable= "@mipmap/msg_selected" />
<!-- 触摸模式下单击时的背景图片-->
<item android:state_focused="false" android:state_pressed="true" android:drawable="@mipmap/msg_selected" />
<!--选中时的图片背景-->
<item android:state_selected="true" android:drawable="@mipmap/msg_selected" />
<item android:drawable="@mipmap/msg_unselected" />
</selector>
用selector好处就是直接调用View.setSelected来处理选中未选中的状态,这里不多述。
下面三个TAB,是fragment组成的,上面两个TAB呢?由于界面比较简单,我这里用ViewPager包裹两个View解决,通过切换TAB选择相应的页面,但是ViewPager是支持滑动的,而QQ是不能滑动的,这样的话,需要重写ViewPager,自定义一个NoTouchViewPager继承ViewPager,如下:
package com.dhl.qqmsgtab.ui;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by dhl on 2017/5/1.
* 不可以滑动的ViewPager
*/
public class NoTouchViewPager extends ViewPager{
public NoTouchViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoTouchViewPager(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
@Override
public void setCurrentItem(int item) {
super.setCurrentItem(item,false);
}
}
通过重写onTouchEvent,返回FALSE,让它不能滑动。
消息页面布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<include
android:id="@+id/top_layout"
layout="@layout/top"/>
<com.dhl.qqmsgtab.ui.NoTouchViewPager
android:id="@+id/view_page"
android:layout_below="@id/top_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.dhl.qqmsgtab.ui.NoTouchViewPager>
</RelativeLayout>
消息页面上面的TAB,包含消息和电话的布局top:
<?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="50dp"
android:background="@color/colorPrimary"
android:orientation="vertical"
android:gravity="center"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center"
android:layout_gravity="center"
android:orientation="horizontal"
>
<TextView
android:id="@+id/message_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:background="@drawable/top_msg_selector"
android:text="消息"
android:textColor="@color/top_msg_color_selector" />
<TextView
android:id="@+id/phone_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@drawable/top_msg_selector"
android:gravity="center"
android:text="电话"
android:textColor="@color/top_msg_color_selector" />
</LinearLayout>
</LinearLayout>
通过下面的方法来选择相应的TAB:
/**
* 选择相应的TAB
* @param view
*/
private void changeSelector(View view)
{
currentBtn.setSelected(false);
view.setSelected(true);
currentBtn = view;
}
消息Fragment的界面:
public class MessageFragment extends Fragment implements View.OnClickListener {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String TAG = MessageFragment.class.getSimpleName();
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private TextView msgText ;
private TextView phoneText ;
private View currentBtn ;
private NoTouchViewPager viewPager ;
private List<View> tabView ;
private OnFragmentInteractionListener mListener;
public MessageFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment MessageFragment.
*/
// TODO: Rename and change types and number of parameters
public static MessageFragment newInstance(String param1, String param2) {
MessageFragment fragment = new MessageFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_message, container, false);
initId(view);
return view;
}
private void initId(View view)
{
msgText = (TextView)view.findViewById(R.id.message_text);
msgText.setOnClickListener(this);
currentBtn = msgText ;
phoneText = (TextView)view.findViewById(R.id.phone_text);
phoneText.setOnClickListener(this);
viewPager = (NoTouchViewPager) view.findViewById(R.id.view_page);
tabView = new ArrayList<>();
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View pageMsg = layoutInflater.inflate(R.layout.page_msg,null);
View pagPhone = layoutInflater.inflate(R.layout.page_phone,null);
tabView.add(pageMsg);
tabView.add(pagPhone);
viewPager.setAdapter(new PagerAdapter() {
@Override
public Object instantiateItem(ViewGroup container, int position) {
Log.e(TAG,container.toString()+"::::::"+viewPager.toString());
//container 就是ViewPager
viewPager.addView(tabView.get(position));
return tabView.get(position);
}
@Override
public int getCount() {
return tabView.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
});
//tabViewmsgText.setSelected(true);
changeSelector(msgText);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.message_text:
changeSelector(msgText);
viewPager.setCurrentItem(0);
break;
case R.id.phone_text:
changeSelector(phoneText);
viewPager.setCurrentItem(1);
break;
}
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
/**
* 选择相应的TAB
* @param view
*/
private void changeSelector(View view)
{
currentBtn.setSelected(false);
view.setSelected(true);
currentBtn = view;
}
}
相应MainActivity的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private MessageFragment messageFragment ;
private ContactFragment contactFragment ;
private NewsFragment newsFragment ;
private FragmentManager fragmentManager ;
/**
* 消息界面布局
*/
private View messageLayout;
/**
* 联系人界面布局
*/
private View contactsLayout;
/**
* 动态界面布局
*/
private View newsLayout;
/**
* 设置界面布局
*/
private View settingLayout;
/**
* 在Tab布局上显示消息图标的控件
*/
private ImageView messageImage;
/**
* 在Tab布局上显示联系人图标的控件
*/
private ImageView contactsImage;
/**
* 在Tab布局上显示动态图标的控件
*/
private ImageView newsImage;
/**
* 在Tab布局上显示消息标题的控件
*/
private TextView messageText;
/**
* 在Tab布局上显示联系人标题的控件
*/
private TextView contactsText;
/**
* 在Tab布局上显示动态标题的控件
*/
private TextView newsText;
/**
* 在Tab布局上显示设置标题的控件
*/
private TextView settingText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* 隐藏标题栏
*/
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
initViews();
setTab(0);
}
private void initViews()
{
messageLayout = (LinearLayout)findViewById(R.id.message_layout);
contactsLayout = (LinearLayout)findViewById(R.id.contacts_layout);
newsLayout = (LinearLayout)findViewById(R.id.news_layout);
messageImage = (ImageView)findViewById(R.id.message_image);
contactsImage = (ImageView)findViewById(R.id.contacts_image);
newsImage = (ImageView)findViewById(R.id.news_image);
messageLayout.setOnClickListener(this);
contactsLayout.setOnClickListener(this);
newsLayout.setOnClickListener(this);
}
/**
* 选择相应的Tab
* @param index
*/
private void setTab(int index)
{
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
hideFragments(fragmentTransaction);
clearSelcetor();
switch (index)
{
case 0:
messageImage.setSelected(true);
if(messageFragment==null)
{
messageFragment = MessageFragment.newInstance("","");
fragmentTransaction.add(R.id.content,messageFragment);
}else
{
fragmentTransaction.show(messageFragment);
}
break;
case 1:
contactsImage.setSelected(true);
if(contactFragment == null)
{
contactFragment = ContactFragment.newInstance("","");
fragmentTransaction.add(R.id.content,contactFragment);
}else
{
fragmentTransaction.show(contactFragment);
}
break;
case 2:
newsImage.setSelected(true);
if(newsFragment == null)
{
newsFragment = NewsFragment.newInstance("","");
fragmentTransaction.add(R.id.content,newsFragment);
}else
{
fragmentTransaction.show(newsFragment);
}
break;
}
fragmentTransaction.commit();
}
/**
* 将所有的Fragment都置为隐藏状态。
*
* @param transaction
* 用于对Fragment执行操作的事务
*/
private void hideFragments(FragmentTransaction transaction) {
if (messageFragment != null) {
transaction.hide(messageFragment);
}
if (contactFragment != null) {
transaction.hide(contactFragment);
}
if (newsFragment != null) {
transaction.hide(newsFragment);
}
}
@Override
public void onClick(View view) {
switch(view.getId())
{
case R.id.message_layout:
setTab(0);
break;
case R.id.contacts_layout:
setTab(1);
break;
case R.id.news_layout:
setTab(2);
break;
}
}
/**
* 全部未选中
*/
private void clearSelcetor()
{
messageImage.setSelected(false);
contactsImage.setSelected(false);
newsImage.setSelected(false);
}
}
源码: 高仿QQTab
最后附上图片来源网址:tab图片