android标签页切换效果,Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面...

感觉 Android 到处都是坑,每个地方都要把人折腾半天。

今天来简单说说 Android之ActionBar、Tabs、Fragment、ViewPager 实现标签页切换并缓存页面

关于他们的介绍就不多说了,网上到处都是,只说关键的部分:

我在开发的时候遇到几个疑难问题,花费大量时间处理,总结如下:

1. 关于 Fragment 内部逻辑处理该写在哪个事件回调部分?

2. ViewPager 页面切换动画卡顿,让我头疼了很久。

3. ViewPager 中如何保存 Fragment 当前视图的状态,让 Tabs 页面切换后不会重新加载,这地方很坑爹

4. ActionBar 中的 tab 很多时如何滚动显示

解答:

一、Fragment 的事件回调:

package com.ai9475.meitian.ui.fragment;

import android.app.Activity;

import android.os.Bundle;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.ListView;

import com.ai9475.meitian.R;

import com.ai9475.meitian.view.DiaryList;

import com.ai9475.util.ZLog;

/**

*

* Created by ZHOUZ on 14-1-21.

*/

public class DiaryListFragment extends BaseFragment

{

private static final String TAG = "DiaryListFragment";

@Override

public void onAttach(Activity activity)

{

ZLog.i(TAG, "onAttach");

super.onAttach(activity);

}

@Override

public void onCreate(Bundle savedInstanceState)

{

ZLog.i(TAG, "onCreate");

super.onCreate(savedInstanceState);

}

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

{

ZLog.i(TAG, "onCreateView");

return inflater.inflate(R.layout.fragment_diary_list, container, false);

}

@Override

public void onActivityCreated(Bundle savedInstanceState)

{

ZLog.i(TAG, "onActivityCreated");

super.onActivityCreated(savedInstanceState);

ZLog.i(TAG, "DiaryList0");

DiaryList diaryList = new DiaryList(

getActivity().getApplicationContext(),

(ListView) getView().findViewById(R.id.diaryListCt)

);

ZLog.i(TAG, "DiaryList load0");

diaryList.load("http://m.ai9475.com/?con=meitian_app");

this.setRetainInstance(true);

}

@Override

public void onStart()

{

ZLog.i(TAG, "onStart");

super.onStart();

}

@Override

public void onResume()

{

ZLog.i(TAG, "onResume");

super.onResume();

}

@Override

public void onPause()

{

ZLog.i(TAG, "onPause");

super.onPause();

}

@Override

public void onStop()

{

ZLog.i(TAG, "onStop");

super.onStop();

}

@Override

public void onDestroyView()

{

ZLog.i(TAG, "onDestroyView");

super.onDestroyView();

}

@Override

public void onDestroy()

{

ZLog.i(TAG, "onDestroy");

super.onDestroy();

}

@Override

public void onDetach()

{

ZLog.i(TAG, "onDetach");

super.onDetach();

}

}

上面的类中的 on 事件就是Fragment主要处理的时间回调,注意复写父类方法时要回调执行父类同名方法,否则会出错

主要复写 onCreateView 方法,返回该 Fragment 所对应的视图对象,这里可以在返回视图对象前进行一些简单的配置,但千万不要写太耗时的处理阻塞UI主线程。

另外 onActivityCreated 方法,是当 activity 的 onCreate 事件结束时的回调,此时当前的Fragment对应的view已经并入到整个布局中,此时可以使用 getView() 方法获取视图对象。

其他几个事件没什么太多可说,有些我也还不是太清楚,还有些动画调用的事件。

二、切换页面卡顿问题

这个问题的产生主要可能是两方面,

1. 没有使用 ViewPager 的缓存,每次切换都重新加载。

2. 加载 Fragment 内部有耗时耗资源的逻辑处理。

这里主要说下第二种情况,我一开始没处理掉 缓存问题时有一个解决办法,

android:id="@+id/tabsViewPager"

android:layout_width="match_parent"

android:layout_height="match_parent"

>

mViewPager = (ViewPager) findViewById(R.id.tabsViewPager);

mViewPager.setOnPageChangeListener(

new ViewPager.SimpleOnPageChangeListener() {

private static final String TAG = "ViewPager.SimpleOnPageChangeListener";

private ArrayList hasLoadedPages = new ArrayList();

@Override

public void onPageSelected(int position) {

ZLog.i(TAG, "onPageSelected position:"+ position);

getSupportActionBar().setSelectedNavigationItem(position);

}

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)

{

ZLog.i(TAG, "onPageScrolled position: "+ position +", positionOffset:"+ positionOffset +", positionOffsetPixels:"+ positionOffsetPixels);

}

@Override

public void onPageScrollStateChanged(int state) {

ZLog.i(TAG, "onPageScrollStateChanged");

int position = mViewPager.getCurrentItem();

switch (state) {

// 正在拖动

case ViewPager.SCROLL_STATE_DRAGGING :

ZLog.i(TAG, "ViewPager.SCROLL_STATE_DRAGGING position:"+ position);

break;

// 拖动释放后正在沉降的过程

case ViewPager.SCROLL_STATE_SETTLING :

ZLog.i(TAG, "ViewPager.SCROLL_STATE_SETTLING position:"+ position);

break;

// 切换动画全部完成结束

case ViewPager.SCROLL_STATE_IDLE :

ZLog.i(TAG, "ViewPager.SCROLL_STATE_IDLE position:"+ position);

// 已加载过则不再加载

if (hasLoadedPages.contains(position)) break;

Fragment fragment = mPager.getFragments().get(position);

runCallback(position, fragment);

hasLoadedPages.add(position);

break;

}

}

public void runCallback(int position, Fragment fragment) {

ZLog.i(TAG, "runCallback");

DiaryList diaryList;

switch (position) {

case 0 :

ZLog.i(TAG, "DiaryList0");

diaryList = new DiaryList(

getApplicationContext(),

(ListView) fragment.getView().findViewById(R.id.diaryListCt)

);

ZLog.i(TAG, "DiaryList load0");

diaryList.load("http://m.ai9475.com/?con=meitian_app");

break;

case 1:

ZLog.i(TAG, "DiaryList1");

diaryList = new DiaryList(

getApplicationContext(),

(ListView) fragment.getView().findViewById(R.id.diaryListCt)

);

ZLog.i(TAG, "DiaryList load1");

diaryList.load("http://m.ai9475.com/?con=meitian_app&act=hot");

break;

case 2:

ZLog.i(TAG, "DiaryList2");

diaryList = new DiaryList(

getApplicationContext(),

(ListView) fragment.getView().findViewById(R.id.diaryListCt)

);

ZLog.i(TAG, "DiaryList load2");

diaryList.load("http://m.ai9475.com/?con=meitian_app");

break;

}

}

}

这里主要用到 public void onPageScrollStateChanged(int state) 页面滚动切换状态变化的事件监听

当滚动动画完全结束 case ViewPager.SCROLL_STATE_IDLE  时再执行 Fragment 的逻辑处理,这样动画就会流畅了。

但经过后来的测试发现有个很简单的解决方案,就是下面要说到的 ViewPager 的缓存功能,其实很简单。

三、缓存 Tabs 页面切换不重新加载数据

我在这地方折腾的最久,而且很多时候无从下手的感觉,网上搜索了很多文章都有说道保存 Fragment 数据和状态,但是没有整整提到如何来保存他的当前view状态,不知道如何保存,当然实际上我还是没搞懂如何仅仅缓存 Fragment 的状态,但对于 ViewPager 缓存 Tab 对应的 Fragment 还是找到了办法,之前花了很大功夫来自己实现,后来偶然发现他居然有个自带的方法

// 设置缓存多少个 Tab对应的 fragment

mViewPager.setOffscreenPageLimit(6);

我测试时用了 6个 listView 加载图片列表数据,切换动画也没有任何卡顿现象,非常流畅,就这么简单一句就搞定了。

配置该项后,ViewPager在切换时将不会清理不可见的 Fragment,不会触发 Fragment 的任何事件,因此也就不会导致其重新加载。

四、ActionBar 中的 Tabs

这个其实不用操作,在tabs数量超过一屏后,例如我现在设置6个宽度超过了屏幕则会变成可以横向滚动的状态,而不需要自己实现,之前不知道在这方面查了很多资料都无果,只知道可以用 tabhost 可以实现,但在ActionBar 里面却又用不了,自己试了下方多个tab才发现原来会自动实现,无语。

android标签页切换效果,Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面..._第1张图片

还是贴上 MainActivity.class 完整代码:

package com.ai9475.meitian.ui;

import android.os.Bundle;

import android.support.v4.app.Fragment;

import android.support.v4.app.FragmentManager;

import android.support.v4.app.FragmentPagerAdapter;

import android.support.v4.app.FragmentStatePagerAdapter;

import android.support.v4.app.FragmentTransaction;

import android.support.v4.view.ViewPager;

import android.support.v7.app.ActionBar;

import android.view.Menu;

import android.widget.ListView;

import com.ai9475.meitian.AppManager;

import com.ai9475.meitian.R;

import com.ai9475.meitian.ui.fragment.DiaryListFragment;

import com.ai9475.meitian.ui.fragment.Test2Fragment;

import com.ai9475.meitian.ui.fragment.Test3Fragment;

import com.ai9475.meitian.view.DiaryList;

import com.ai9475.util.ZLog;

import java.util.ArrayList;

public class MainActivity extends BaseActivity

{

private static final String TAG = "MainActivity";

private MyTabsPagerAdapter mPager;

private ViewPager mViewPager;

@Override

protected void onCreate(Bundle savedInstanceState)

{

ZLog.i(TAG, "start");

// 执行父级初始化方法

super.onCreate(savedInstanceState);

//requestWindowFeature(Window.FEATURE_NO_TITLE);

ZLog.i(TAG, "setContentView");

setContentView(R.layout.activity_main);

// 滑动页面视图配置

ZLog.i(TAG, "MyTabsPagerAdapter start");

mPager = new MyTabsPagerAdapter(getSupportFragmentManager());

mPager.getFragments().add(new DiaryListFragment());

mPager.getFragments().add(new Test2Fragment());

mPager.getFragments().add(new Test3Fragment());

mPager.getFragments().add(new Test3Fragment());

mPager.getFragments().add(new Test3Fragment());

mPager.getFragments().add(new Test3Fragment());

// 滑动分页容器

mViewPager = (ViewPager) findViewById(R.id.tabsViewPager);

// 设置缓存多少个 fragment

mViewPager.setOffscreenPageLimit(6);

mViewPager.setAdapter(mPager);

// 页面滑动事件

mViewPager.setOnPageChangeListener(

new ViewPager.SimpleOnPageChangeListener() {

private static final String TAG = "ViewPager.SimpleOnPageChangeListener";

private ArrayList hasLoadedPages = new ArrayList();

@Override

public void onPageSelected(int position) {

ZLog.i(TAG, "onPageSelected position:"+ position);

getSupportActionBar().setSelectedNavigationItem(position);

}

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)

{

ZLog.i(TAG, "onPageScrolled position: "+ position +", positionOffset:"+ positionOffset +", positionOffsetPixels:"+ positionOffsetPixels);

}

@Override

public void onPageScrollStateChanged(int state) {

ZLog.i(TAG, "onPageScrollStateChanged");

int position = mViewPager.getCurrentItem();

switch (state) {

// 正在拖动

case ViewPager.SCROLL_STATE_DRAGGING :

ZLog.i(TAG, "ViewPager.SCROLL_STATE_DRAGGING position:"+ position);

break;

// 拖动释放后正在沉降的过程

case ViewPager.SCROLL_STATE_SETTLING :

ZLog.i(TAG, "ViewPager.SCROLL_STATE_SETTLING position:"+ position);

break;

// 切换动画全部完成结束

case ViewPager.SCROLL_STATE_IDLE :

ZLog.i(TAG, "ViewPager.SCROLL_STATE_IDLE position:"+ position);

/*if (hasLoadedPages.contains(position)) break;

Fragment fragment = mPager.getFragments().get(position);

runCallback(position, fragment);

hasLoadedPages.add(position);*/

break;

}

}

public void runCallback(int position, Fragment fragment) {

ZLog.i(TAG, "runCallback");

DiaryList diaryList;

switch (position) {

case 0 :

ZLog.i(TAG, "DiaryList0");

diaryList = new DiaryList(

getApplicationContext(),

(ListView) fragment.getView().findViewById(R.id.diaryListCt)

);

ZLog.i(TAG, "DiaryList load0");

diaryList.load("http://m.ai9475.com/?con=meitian_app");

break;

case 1:

ZLog.i(TAG, "DiaryList1");

diaryList = new DiaryList(

getApplicationContext(),

(ListView) fragment.getView().findViewById(R.id.diaryListCt)

);

ZLog.i(TAG, "DiaryList load1");

diaryList.load("http://m.ai9475.com/?con=meitian_app&act=hot");

break;

case 2:

ZLog.i(TAG, "DiaryList2");

diaryList = new DiaryList(

getApplicationContext(),

(ListView) fragment.getView().findViewById(R.id.diaryListCt)

);

ZLog.i(TAG, "DiaryList load2");

diaryList.load("http://m.ai9475.com/?con=meitian_app");

break;

}

}

}

);

ActionBar actionBar = getSupportActionBar();

actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

// Tab 页面切换

MyTabListener listener = new MyTabListener();

// 默认的首页 tab

ActionBar.Tab indexTab = actionBar.newTab()

.setText(getString(R.string.tab_index))

.setTabListener(listener);

actionBar.addTab(indexTab);

actionBar.addTab(actionBar.newTab()

.setText(getString(R.string.tab_hot))

.setTabListener(listener)

);

actionBar.addTab(actionBar.newTab()

.setText(getString(R.string.tab_tag))

.setTabListener(listener)

);

actionBar.addTab(actionBar.newTab()

.setText(getString(R.string.tab_tag))

.setTabListener(listener)

);

actionBar.addTab(actionBar.newTab()

.setText(getString(R.string.tab_tag))

.setTabListener(listener)

);

actionBar.addTab(actionBar.newTab()

.setText(getString(R.string.tab_tag))

.setTabListener(listener)

);

// 显示首页

indexTab.select();

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.main, menu);

return true;

}

private class MyTabListener implements ActionBar.TabListener

{

@Override

public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft)

{

int position = tab.getPosition();

ZLog.i(TAG, "tab selected: "+ position);

// 数据通信

/*Bundle bundle = new Bundle();

Fragment fragment = mPager.getItem(tab.getPosition());

Toast.makeText(getApplicationContext(), "position:"+ tab.getPosition(), Toast.LENGTH_SHORT).show();

fragment.setArguments(bundle);

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();

fragmentTransaction.add(R.id.fragmentContainer, fragment);

fragmentTransaction.commit();*/

mViewPager.setCurrentItem(position);

}

@Override

public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {

ZLog.i(TAG, "tab reselected: "+ tab.getPosition());

}

@Override

public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft)

{

ZLog.i(TAG, "tab unselected: "+ tab.getPosition());

}

};

public class MyTabsPagerAdapter extends FragmentPagerAdapter

{

private ArrayList mFragments = new ArrayList();

public MyTabsPagerAdapter(FragmentManager fm) {

super(fm);

}

public ArrayList getFragments() {

return this.mFragments;

}

@Override

public Fragment getItem(int i) {

return this.mFragments.get(i);

}

@Override

public int getCount() {

return this.mFragments.size();

}

}

}

你可能感兴趣的:(android标签页切换效果)