目前主流的app都在下面有一排按钮来选择切换页面,可以使用Fragment来实现Tab效果来达到目的,要想用Fragment 功能必须先让activity继承FragmentActivity,其原因是里面包含了Fragment运作的FragmentManager接口的实现类 FragmentManagerImpl ,由这个类管理所有Fragment的显示、隐藏,下面我们实现一个有首页和设置两个界面的切换效果
重叠问题描述
在android中应用程序异常结束的可能性是非常大的,比如一键清理,省电功能等。它们会直接就把你的应用给关闭啦,应用非正常关闭后你的应用里的activity都会被回收,但是应用里的Fragment却还存在并没有回收掉,当你再次打开的时候activity会重新创建,创建的时候它会自动找到之前没有销毁的Fragment来加载直接显示到Tab里面。这个时候你的代码初始化里面还有一个创建Fragment的代码,会再创建一次fragment,之前的Fragment就是野的啦没法控制啦,一直就在那显示着。知道啦原因下面说处理方法。
解决重叠问题
重写Activity的onAttachFragment这个方法,它带啦一个参数Fragment就是加载之前已经存在的对象,我们判断下是不是我们对应的tab对象是的话就直接设置上去,然后在创建tab的初始化函数里判断下只在在tab对象是null的时候才去实例化Fragment对象
示例代码
请自己引入android.support.v4 支持库
首先创建两个界面的类继承Fragment,首页类HomeFragment和设置类SetFragment
HomeFragment.javapackage com.androidnodesocket;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Administrator on 2017-10-16.
*/
public class HomeFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.activity_home, container, false);
//取xml中的元素方法(跟activity中有一些不一样)
// searchbtn = (TextView) view.findViewById(R.id.tv_top_title);
return view;
}
}
SetFragment.javapackage com.androidnodesocket;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Administrator on 2017-10-16.
*/
public class SetFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.activity_set, container, false);
return view;
}
}
布局文件 activity_home.xml和activity_set.xml这两个文件很简单就一个字符串就不贴代码啦自己创建好就行,然后就是创建一个主的框架类来加载这两个页面起个名字 MainFragmentActivitypackage com.androidnodesocket;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.widget.Button;
/**
* Created by Administrator on 2017-10-16.
*/
public class MainFragmentActivity extends FragmentActivity {
private FragmentManager fmg;
private Fragment fmHome,fmSet;
private Button btnHome,btnSet;
@Override
public void onAttachFragment(android.app.Fragment fragment) {
super.onAttachFragment(fragment);
//下面代码处理系统因为省电或其它原因关闭activity后fragment没有关闭再次创建activity时fragment重叠的问题
if (fmHome == null && fragment instanceof HomeFragment) {
fmHome = (HomeFragment) fragment;
} else if (fmSet == null && fragment instanceof SetFragment) {
fmSet = (SetFragment) fragment;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mainfragment);
btnHome = (LinearLayout) findViewById(R.id.nav_home);
btnSet = (LinearLayout) findViewById(R.id.nav_set);
//初始化管理器
fmg = getSupportFragmentManager();
if(fmHome == null){
fmHome = new HomeFragment();
}
if(fmSet==null){
fmSet = new SetFragment();
}
//初始化的时候需要显示一个fragment,假设我们显示第二个fragment
//向容器中添加或者替换fragment时必须 开启事务 操作完成后 提交事务
FragmentTransaction ft = fmg.beginTransaction();
ft.add(R.id.main_container, fmHome).commit();
}
/**
* 单击导航调用此方法
*
* @param v
*/
public void clickNav(View v) {
int id = v.getId();
FragmentTransaction ft = fmg.beginTransaction();
switch (id) {
case R.id.nav_home:
if (!fmHome.isAdded()) {
ft.hide(fmSet).show(fmHome).add(R.id.main_container, fmHome).commit();
} else {
ft.hide(fmSet).show(fmHome).commit();
}
break;
case R.id.nav_set:
if (!fmSet.isAdded()) {
ft.hide(fmHome).show(fmSet).add(R.id.main_container, fmSet).commit();
} else {
ft.hide(fmHome).show(fmSet).commit();
}
break;
}
}
}
布局文件 activity_mainfragment.xml,里面设计好导航的位置,并且还有一个加载界面的容器id为main_container
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF">
android:id="@+id/main_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="@+id/menu_line">
android:id="@+id/menu_line"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:layout_above="@+id/menu_bottom"
android:background="@color/bg_Gray"
/>
android:id="@+id/menu_bottom"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:paddingTop="8dp">
android:id="@+id/nav_home"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:onClick="clickNav"
android:text="首页" />
android:id="@+id/nav_set"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:onClick="clickNav"
android:text="设置" />
可以啦,下面是效果图

加一个过滤的动画,首先要定义进出的xml特效文件,把这些文件放言 入res/anim文件夹中
in_from_left.xml<?xml version="1.0" encoding="utf-8"?>
android:interpolator="@android:anim/accelerate_interpolator">
android:fromXDelta="-100%p"
android:toXDelta="0%p"
android:duration="200" />
in_from_right.xml<?xml version="1.0" encoding="utf-8"?>
android:interpolator="@android:anim/accelerate_interpolator">
android:fromXDelta="100%p"
android:toXDelta="0%p"
android:duration="200" />
out_from_left.xml<?xml version="1.0" encoding="utf-8"?>
android:interpolator="@android:anim/accelerate_interpolator">
android:fromXDelta="0%p"
android:toXDelta="-100%p"
android:duration="200" />
out_from_right.xml<?xml version="1.0" encoding="utf-8"?>
android:interpolator="@android:anim/accelerate_interpolator">
android:fromXDelta="0%p"
android:toXDelta="100%p"
android:duration="200" />
修改事件处理代码/**
* 单击导航调用此方法
*
* @param v
*/
public void clickNav(View v) {
int id = v.getId();
FragmentTransaction ft = fmg.beginTransaction();
switch (id) {
case R.id.nav_home:
ft.setCustomAnimations(R.anim.in_from_left,0, 0, R.anim.out_from_left);
if (!fmHome.isAdded()) {
ft.hide(fmSet).show(fmHome).add(R.id.main_container, fmHome).commit();
} else {
ft.hide(fmSet).show(fmHome).commit();
}
break;
case R.id.nav_set:
ft.setCustomAnimations(R.anim.in_from_right,0,0, R.anim.out_from_right);
if (!fmSet.isAdded()) {
ft.hide(fmHome).show(fmSet).add(R.id.main_container, fmSet).commit();
} else {
ft.hide(fmHome).show(fmSet).commit();
}
break;
}
}

ft.setCustomAnimations 关于这个函数的参数传递中间的两个直接传0 ,传其它值的话动画就会错乱(是个坑弄啦好久都没弄好)。关于原因请自行百度,谷歌查询