首页 > 其他分享 >Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面

Android之ActionBar、Tabs、Fragment、ViewPager实现标签页切换并缓存页面

时间:2023-05-20 14:33:08浏览次数:54  
标签:ActionBar Tabs ViewPager TAG import ZLog position public

感觉 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.support.v4.view.ViewPager
         android:id = "@+id/tabsViewPager"
         android:layout_width = "match_parent"
         android:layout_height = "match_parent"
         >
     </ android.support.v4.view.ViewPager >


mViewPager = (ViewPager) findViewById(R.id.tabsViewPager);
mViewPager.setOnPageChangeListener(
                 new ViewPager.SimpleOnPageChangeListener() {
                     private static final String TAG = "ViewPager.SimpleOnPageChangeListener" ;
                     private ArrayList hasLoadedPages = new ArrayList<Integer>();
                     @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才发现原来会自动实现,无语。




还是贴上 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<Integer>();
                     @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<Fragment> mFragments = new ArrayList<Fragment>();
 
         public MyTabsPagerAdapter(FragmentManager fm) {
             super (fm);
         }
 
         public ArrayList<Fragment> getFragments() {
             return this .mFragments;
         }
 
         @Override
         public Fragment getItem( int i) {
             return this .mFragments.get(i);
         }
 
         @Override
         public int getCount() {
             return this .mFragments.size();
         }
     }
}

文章知识点与官方知识档


标签:ActionBar,Tabs,ViewPager,TAG,import,ZLog,position,public
From: https://blog.51cto.com/u_16120380/6317597

相关文章

  • AntDesign Blaozr标签页ReuseTabs的使用以及授权失败的坑
    123<Authorized><ReuseTabsDraggableSize="TabSize.Small"/></Authorized><NotAuthorized>@{NavigationManager.NavigateTo("......
  • 【HarmonyOS】【JS】Tabs如何设置区分TabBar和TabContent的分割线不显示
    【关键字】Tabs,分割线 【问题描述】使用JS开发HarmonyOS应用时,使用Tabs组件,默认自带TabBar和TabContent的蓝色分割线,由于蓝色分割线样式不可设置,若不想要此蓝色分割线,如何去除蓝色分割线? 【问题分析】1、若JS使用Tabs,蓝色分割线为组件自带样式,暂不支持属性支持显示与隐藏......
  • 使用 youth5201314:banner 库时出现 ViewPager 或 xandroid 报错
    使用youth5201314:banner这个库的1.4.10版本开发时,Build时报错找不到android.support.v4.view.ViewPager的类文件找不到androidx.fragment.app.Fragment的类文件需要在Project的gradle.properties配置文件中加一行,用于自动迁移第三方库android.enableJetifier=......
  • 基于JQuery的7款选项卡(Tabs)实例
    基于JQuery的7款选项卡(Tabs)实例1.jQuery选项卡界面/选项卡结构菜单教程这种类型的菜单在网页设计与开发中非常著名的。此片教程是向大家展示如何使用jQuery的向下滑动/向上滑动效果创建属于你自己的选项卡菜单。要非常留心此演示哟,你一定会喜欢上它的。演示|下载|......
  • ViewPager2+Fragment+FragmentStateAdapter遇到系统主题更换时Fragment数据丢失
    1.问题描述:在ViewPager设置壁纸,导致Activity获取Fragment数据丢失2.解决方案:设置 vp.isSaveEnabled=false  ,设置不保存,在适配器中销毁item 引发问题:vp重建之后,会丢失之前所在的位置解决方案:Activity onSaveInstanceState中保存数据,在 o......
  • viewPager2页面的切换
    使用流程:  1.定义ViewPager  2.为ViewPager创建AdapterViewPagerAdapterpackagecom.example.viewpagerandfragment;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.RelativeLayout;importand......
  • AndroidBanner - ViewPager 03
    AndroidBanner-ViewPager03上一篇文章,描述了如何实现自动轮播的,以及手指触摸的时候停止轮播,抬起继续轮播,其实还遗留了一些问题:当banner不可见的时候,也需要停止轮播给banner设置点击事件,长时间的触摸也会被默认是一个点击事件这篇文章就来解决这些问题,并处理一下banner的......
  • 一个类似Tabs的控件SegmentControl
    packagecom.ql.view;importjava.util.HashMap;importjava.util.Map;importandroid.content.Context;importandroid.graphics.Color;importandroid.util.AttributeSet;importandroid.view.MotionEvent;importandroid.view.View;importandroid.widget.Linea......
  • 为ViewPager设置SimpleViewPagerIndicator
    说到ViewPagerIndicator,网上有很多专门的开源库;我这里重提一下,只是想试试它的实现方法;记录下来,可以以后快速的修改迭代~~~很简单的一个类:importandroid.content.Context;importandroid.graphics.Canvas;importandroid.graphics.Color;importan......
  • 缓存式的ViewPager&和其他手势控件冲突的解决办法
    一般来说ViewPager如果有很多页的话,会加载它的上一页,当前页和下一页,当从n页以后再想回到第一页,就会再加载一次,这样第一页很多操作后的数据就会被重置,原因是在PagerAdapter的destroyItem经常会移除View,类似下面这样的代码:@Overridepublicvoiddest......