android使用FragmentActivity、Fragment实现tab切换的功能

来源:赵克立博客 分类: Android 标签:Android发布时间:2017-10-15 18:41:06最后更新:2017-10-17 18:17:55浏览:3267
版权声明:
本文为博主原创文章,转载请声明原文链接...谢谢。o_0。
更新时间:
2017-10-17 18:17:55
温馨提示:
学无止境,技术类文章有它的时效性,请留意文章更新时间,如发现内容有误请留言指出,防止别人"踩坑",我会及时更新文章

目前主流的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.java

package 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.java

package 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这两个文件很简单就一个字符串就不贴代码啦自己创建好就行,然后就是创建一个主的框架类来加载这两个页面起个名字 MainFragmentActivity

package 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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#FFFFFF">
    <RelativeLayout
        android:id="@+id/main_container"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@+id/menu_line"></RelativeLayout>
    <View
        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"
        />
    <LinearLayout
        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">
        <Button
            android:id="@+id/nav_home"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:onClick="clickNav"
            android:text="首页" />
        <Button
            android:id="@+id/nav_set"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:onClick="clickNav"
            android:text="设置" />
    </LinearLayout>
</RelativeLayout>

可以啦,下面是效果图

GIF.gif

加一个过滤的动画,首先要定义进出的xml特效文件,把这些文件放言 入res/anim文件夹中

in_from_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
    android:interpolator="@android:anim/accelerate_interpolator">
    <translate 
        android:fromXDelta="-100%p"
        android:toXDelta="0%p"
        android:duration="200" />
</set>


in_from_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
    android:interpolator="@android:anim/accelerate_interpolator">
    <translate 
        android:fromXDelta="100%p"
        android:toXDelta="0%p"
        android:duration="200" />
</set>

out_from_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
    android:interpolator="@android:anim/accelerate_interpolator">
    <translate 
        android:fromXDelta="0%p" 
        android:toXDelta="-100%p"
        android:duration="200" />
</set>

out_from_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
    android:interpolator="@android:anim/accelerate_interpolator">
    <translate 
        android:fromXDelta="0%p" 
        android:toXDelta="100%p"
        android:duration="200" />
</set>

修改事件处理代码

/**
 * 单击导航调用此方法
 *
 * @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;
    }
}

GIF.gif


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


微信号:kelicom QQ群:215861553 紧急求助须知
Win32/PHP/JS/Android/Python