最近项目中有一个需求,类似网易、腾讯新闻客户端的频道管理界面,可以对频道进行排序、增加、删除功能。网上也找了相关的资料,但是发现他们都有同一个问题,就是改变频道的顺序后,对应频道的内容并不会改变。这是FragmentPagerAdapter的notifyDataSetChanged()方法没有效果导致的,知道这个原因,下面提供解决方法。
这个主界面的源码:
    public class MainActivity extends FragmentActivity implements View.OnClickListener {private TabLayout mNewsTab;private ViewPager mNewsVp;/** 调整返回的RESULTCODE */public final static int CHANNELRESULT = 10;private ArrayList<ChannelItem> mUserChannelList;//    private List<String> titleArray;private List<NewsFragment> mListFragment;private NewsVpAdapter mNewsVpAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//去掉系统标题requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);findViewById(R.id.more_columns_tv).setOnClickListener(this);initView();}private void initView() {mNewsTab = (TabLayout) findViewById(R.id.news_tab);mNewsVp = (ViewPager) findViewById(R.id.news_vp);findViewById(R.id.more_columns_tv).setOnClickListener(this);mListFragment = new ArrayList<>();//设置TabLayout的模式mNewsTab.setTabMode(TabLayout.MODE_SCROLLABLE);mUserChannelList = ((ArrayList<ChannelItem>) ChannelManage.getManage(AppContext.getApp().getSQLHelper()).getUserChannel());intData();mNewsVpAdapter = new NewsVpAdapter(getSupportFragmentManager(),mListFragment,mUserChannelList);mNewsVp.setAdapter(mNewsVpAdapter);//TabLayout加载viewpagermNewsTab.setupWithViewPager(mNewsVp);}private void intData() {for (ChannelItem channelItem : mUserChannelList) {NewsFragment newsFragment = new NewsFragment();Bundle bundle = new Bundle();//设置tag,区分不同频道的Fragmentbundle.putSerializable("tag", channelItem);newsFragment.setArguments(bundle);mListFragment.add(newsFragment);}//为TabLayout添加tab名称initColumn();}private void initColumn() {for (int i = 0; i < mUserChannelList.size(); i++) {mNewsTab.addTab(mNewsTab.newTab().setText(mUserChannelList.get(i).getName()));}}@Overridepublic void onClick(View v) {//打开频道管理ActivityIntent intent_channel = new  Intent(this, ChannelActivity.class);startActivityForResult(intent_channel, CHANNELRESULT);}@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {switch (requestCode) {case CHANNELRESULT://频道发生改变后,重新设置Fragmentif(resultCode == CHANNELRESULT){selectTab(0);setChangelView();}break;default:break;}super.onActivityResult(requestCode, resultCode, data);}private void selectTab(int position) {mNewsTab.getTabAt(position).select();}private void setChangelView() {mListFragment.clear();mNewsTab.removeAllTabs();mUserChannelList = ((ArrayList<ChannelItem>) ChannelManage.getManage(AppContext.getApp().getSQLHelper()).getUserChannel());List<Integer> integers = mNewsVpAdapter.getIntegers();for (int i = 0; i < mUserChannelList.size(); i++) {ChannelItem channelItem = mUserChannelList.get(i);if (integers.contains(i)) {//当Adapter上position为i的Fragment已经被初始化,就给他设置一个需要重新初始化的标记channelItem.setNeedUpdate(true);} else {channelItem.setNeedUpdate(false);}NewsFragment newsFragment = new NewsFragment();Bundle bundle = new Bundle();bundle.putSerializable("tag", channelItem);newsFragment.setArguments(bundle);newsFragment.setIsUpdate(true);mListFragment.add(newsFragment);}initColumn();selectTab(0);mNewsVpAdapter.setData(mListFragment,mUserChannelList);mNewsVp.setCurrentItem(0, false);mNewsTab.setScrollPosition(0, 0, true);mNewsTab.scrollTo(0,0);Log.e("size",mNewsTab.getTabCount()+"tab");// 根据Tab的长度动态设置TabLayout的模式dynamicSetTabLayoutMode(mNewsTab);}/*** 根据Tab合起来的长度动态修改tab的模式** @param tabLayout TabLayout*/public static void dynamicSetTabLayoutMode(TabLayout tabLayout) {int tabTotalWidth = 0;for (int i = 0; i < tabLayout.getChildCount(); i++) {final View view = tabLayout.getChildAt(i);view.measure(0, 0);tabTotalWidth += view.getMeasuredWidth();}if (tabTotalWidth <= getScreenSize(tabLayout.getContext()).x) {tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);tabLayout.setTabMode(TabLayout.MODE_FIXED);} else {tabLayout.setTabGravity(TabLayout.GRAVITY_CENTER);tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);}}/*** 获取屏幕尺寸** @param context 上下文* @return 屏幕尺寸像素值,下标为0的值为宽,下标为1的值为高*/public static Point getScreenSize(Context context) {// 获取屏幕宽高WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Point screenSize = new Point();wm.getDefaultDisplay().getSize(screenSize);return screenSize;}
}
频道管理Activity的源码:
    public class ChannelActivity extends Activity implements OnItemClickListener, View.OnClickListener {public static String TAG = "ChannelActivity";/*** 用户栏目的GRIDVIEW*/private DragGrid userGridView;/*** 其它栏目的GRIDVIEW*/private OtherGridView otherGridView;/*** 用户栏目对应的适配器,可以拖动*/DragAdapter userAdapter;/*** 其它栏目对应的适配器*/OtherAdapter otherAdapter;/*** 其它栏目列表*/ArrayList<ChannelItem> otherChannelList = new ArrayList<ChannelItem>();/*** 用户栏目列表*/ArrayList<ChannelItem> userChannelList = new ArrayList<ChannelItem>();/*** 是否在移动,由于这边是动画结束后才进行的数据更替,设置这个限制为了避免操作太频繁造成的数据错乱。*/boolean isMove = false;/*** 手势监听*/GestureDetector mGestureDetector;/*** 是否需要监听手势关闭功能*/private boolean mNeedBackGesture = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//去掉系统标题requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_channel);initGestureDetector();initView();initData();}private void initGestureDetector() {if (mGestureDetector == null) {mGestureDetector = new GestureDetector(getApplicationContext(),new BackGestureListener(this));}}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubif (mNeedBackGesture) {return mGestureDetector.onTouchEvent(ev) || super.dispatchTouchEvent(ev);}return super.dispatchTouchEvent(ev);}/*** 初始化数据*/private void initData() {userChannelList = ((ArrayList<ChannelItem>) ChannelManage.getManage(AppContext.getApp().getSQLHelper()).getUserChannel());otherChannelList = ((ArrayList<ChannelItem>) ChannelManage.getManage(AppContext.getApp().getSQLHelper()).getOtherChannel());userAdapter = new DragAdapter(this, userChannelList);userGridView.setAdapter(userAdapter);otherAdapter = new OtherAdapter(this, otherChannelList);otherGridView.setAdapter(otherAdapter);//设置GRIDVIEW的ITEM的点击监听otherGridView.setOnItemClickListener(this);userGridView.setOnItemClickListener(this);}/*** 初始化布局*/private void initView() {userGridView = (DragGrid) findViewById(R.id.userGridView);otherGridView = (OtherGridView) findViewById(R.id.otherGridView);findViewById(R.id.title_bar).findViewById(R.id.back).setOnClickListener(this);}/*** GRIDVIEW对应的ITEM点击监听接口*/@Overridepublic void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {//如果点击的时候,之前动画还没结束,那么就让点击事件无效if (isMove) {return;}switch (parent.getId()) {case R.id.userGridView://position为 0,1 的不可以进行任何操作
//          if (position != 0 && position != 1) {if (position != 0) {final ImageView moveImageView = getView(view);if (moveImageView != null) {TextView newTextView = (TextView) view.findViewById(R.id.text_item);final int[] startLocation = new int[2];newTextView.getLocationInWindow(startLocation);final ChannelItem channel = ((DragAdapter) parent.getAdapter()).getItem(position);//获取点击的频道内容otherAdapter.setVisible(false);//添加到最后一个otherAdapter.addItem(channel);new Handler().postDelayed(new Runnable() {public void run() {try {int[] endLocation = new int[2];//获取终点的坐标otherGridView.getChildAt(otherGridView.getLastVisiblePosition()).getLocationInWindow(endLocation);MoveAnim(moveImageView, startLocation, endLocation, channel, userGridView);userAdapter.setRemove(position);} catch (Exception localException) {}}}, 50L);}}break;case R.id.otherGridView:final ImageView moveImageView = getView(view);if (moveImageView != null) {TextView newTextView = (TextView) view.findViewById(R.id.text_item);final int[] startLocation = new int[2];newTextView.getLocationInWindow(startLocation);final ChannelItem channel = ((OtherAdapter) parent.getAdapter()).getItem(position);userAdapter.setVisible(false);//添加到最后一个userAdapter.addItem(channel);new Handler().postDelayed(new Runnable() {public void run() {try {int[] endLocation = new int[2];//获取终点的坐标userGridView.getChildAt(userGridView.getLastVisiblePosition()).getLocationInWindow(endLocation);MoveAnim(moveImageView, startLocation, endLocation, channel, otherGridView);otherAdapter.setRemove(position);} catch (Exception localException) {}}}, 50L);}break;default:break;}}/*** 点击ITEM移动动画** @param moveView* @param startLocation* @param endLocation* @param moveChannel* @param clickGridView*/private void MoveAnim(View moveView, int[] startLocation, int[] endLocation, final ChannelItem moveChannel,final GridView clickGridView) {int[] initLocation = new int[2];//获取传递过来的VIEW的坐标moveView.getLocationInWindow(initLocation);//得到要移动的VIEW,并放入对应的容器中final ViewGroup moveViewGroup = getMoveViewGroup();final View mMoveView = getMoveView(moveViewGroup, moveView, initLocation);//创建移动动画TranslateAnimation moveAnimation = new TranslateAnimation(startLocation[0], endLocation[0], startLocation[1],endLocation[1]);moveAnimation.setDuration(300L);//动画时间//动画配置AnimationSet moveAnimationSet = new AnimationSet(true);moveAnimationSet.setFillAfter(false);//动画效果执行完毕后,View对象不保留在终止的位置moveAnimationSet.addAnimation(moveAnimation);mMoveView.startAnimation(moveAnimationSet);moveAnimationSet.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {isMove = true;}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {moveViewGroup.removeView(mMoveView);// instanceof 方法判断2边实例是不是一样,判断点击的是DragGrid还是OtherGridViewif (clickGridView instanceof DragGrid) {otherAdapter.setVisible(true);otherAdapter.notifyDataSetChanged();userAdapter.remove();} else {userAdapter.setVisible(true);userAdapter.notifyDataSetChanged();otherAdapter.remove();}isMove = false;}});}/*** 获取移动的VIEW,放入对应ViewGroup布局容器** @param viewGroup* @param view* @param initLocation* @return*/private View getMoveView(ViewGroup viewGroup, View view, int[] initLocation) {int x = initLocation[0];int y = initLocation[1];viewGroup.addView(view);LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);mLayoutParams.leftMargin = x;mLayoutParams.topMargin = y;view.setLayoutParams(mLayoutParams);return view;}/*** 创建移动的ITEM对应的ViewGroup布局容器*/private ViewGroup getMoveViewGroup() {ViewGroup moveViewGroup = (ViewGroup) getWindow().getDecorView();LinearLayout moveLinearLayout = new LinearLayout(this);moveLinearLayout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));moveViewGroup.addView(moveLinearLayout);return moveLinearLayout;}/*** 获取点击的Item的对应View,** @param view* @return*/private ImageView getView(View view) {view.destroyDrawingCache();view.setDrawingCacheEnabled(true);Bitmap cache = Bitmap.createBitmap(view.getDrawingCache());view.setDrawingCacheEnabled(false);ImageView iv = new ImageView(this);iv.setImageBitmap(cache);return iv;}/*** 退出时候保存选择后数据库的设置*/private void saveChannel() {ChannelManage.getManage(AppContext.getApp().getSQLHelper()).deleteAllChannel();ChannelManage.getManage(AppContext.getApp().getSQLHelper()).saveUserChannel(userAdapter.getChannnelLst());ChannelManage.getManage(AppContext.getApp().getSQLHelper()).saveOtherChannel(otherAdapter.getChannnelLst());}@Overridepublic void onClick(View v) {saveChannel();if (userAdapter.isListChanged()) {Intent intent = new Intent(getApplicationContext(), MainActivity.class);setResult(MainActivity.CHANNELRESULT, intent);finish();Log.d(TAG, "数据发生改变");} else {
//            super.onBackPressed();}finish();}/*** 返回手势监听接口*/public class BackGestureListener implements GestureDetector.OnGestureListener {ChannelActivity activity;public BackGestureListener(ChannelActivity activity) {this.activity = activity;}@Overridepublic boolean onDown(MotionEvent e) {// TODO Auto-generated method stubreturn false;}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {// TODO Auto-generated method stubreturn false;}@Overridepublic void onLongPress(MotionEvent e) {// TODO Auto-generated method stub}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,float distanceY) {if ((e2.getX() - e1.getX()) > 100 && Math.abs(e1.getY() - e2.getY()) < 60) {activity.onBackPressed();return true;}return false;}@Overridepublic void onShowPress(MotionEvent e) {// TODO Auto-generated method stub}@Overridepublic boolean onSingleTapUp(MotionEvent e) {// TODO Auto-generated method stubreturn false;}}
}
当你更新里fragment List集合后调用fragmentpageadpater的notifyDataSetChanged方法时发现数据根本就没有刷新。通过对fragmentpageadapter的源码查看你会在instantiateItem方法里面发现这一段:
    // Do we already have this fragment?String name = makeFragmentName(container.getId(), position);Fragment fragment = mFragmentManager.findFragmentByTag(name);if (fragment != null) {if (DEBUG) Log.v(TAG, "Attaching item #" + position + ": f=" + fragment);mCurTransaction.attach(fragment);} else {fragment = getItem(position);if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);mCurTransaction.add(container.getId(), fragment,makeFragmentName(container.getId(), position));}
原来他会先去FragmentManager里面去查找有没有相关的fragment如果有就直接使用如果没有才会触发fragmentpageadapter的getItem方法获取一个fragment。所以你更新的fragmentList集合是没有作用的,解决方法是在instantiateItem方法里作文章,具体请看源码:
    public class NewsVpAdapter extends FragmentPagerAdapter {private List<NewsFragment> list_fragment; //fragment列表private List<ChannelItem> channelItems; //tab名的列表private FragmentManager fm;public boolean fragmentsUpdateFlag;/**保存已经被初始化的Fragment所在的position*/private List<Integer> integers = new ArrayList<>();public List<Integer> getIntegers() {return integers;}public void setIntegers(List<Integer> integers) {this.integers = integers;}public NewsVpAdapter(FragmentManager fm, List<NewsFragment> list_fragment, List<ChannelItem> channelItems) {super(fm);this.list_fragment = list_fragment;this.channelItems = channelItems;this.fm = fm;}public void setData(List<NewsFragment> list_fragment, List<ChannelItem> channelItems) {this.list_fragment = list_fragment;this.channelItems = channelItems;fragmentsUpdateFlag = true;notifyDataSetChanged();}@Overridepublic int getCount() {return list_fragment.size();}@Overridepublic int getItemPosition(Object object) {return POSITION_NONE;}//此方法用来显示tab上的名字@Overridepublic CharSequence getPageTitle(int position) {return channelItems.get(position).getName();}int count;@Overridepublic Fragment getItem(int position) {return list_fragment.get(position);}@Overridepublic Object instantiateItem(ViewGroup container, int position) {if (!integers.contains(position)) {//如果这个positionFragment上的没有被初始化,就把这个position添加到集合中integers.add(position);}//得到缓存的fragmentNewsFragment itemFragment = (NewsFragment) super.instantiateItem(container, position);ChannelItem channelItem = channelItems.get(position);//得到tag❶,这点很重要String tag = itemFragment.getTag();if (channelItem.getNeedUpdate() && integers.contains(position)) {//如果这个fragment需要更新FragmentTransaction ft = fm.beginTransaction();//得到tag,这点很重要ft.remove(itemFragment);//移除旧的fragmentitemFragment = (NewsFragment) list_fragment.get(position);//添加新fragment时必须用前面获得的tag,这点很重要ft.add(container.getId(), itemFragment, tag);ft.attach(itemFragment);ft.commitAllowingStateLoss();channelItem.setNeedUpdate(false);}return itemFragment;}}
代码注释得很清楚了,主要思路就是用新的fragment替换FragmentManager里缓存的旧的fragment,重点解释❶的地方,
    String name = makeFragmentName(container.getId(), position);Fragment fragment = mFragmentManager.findFragmentByTag(name);
说明fragmentpageadapter内部是用tag识别fragment的,并且有它自己的一套算法用于生成tag,所以我们这里必须用它生成的tag来添加新的fragment,否则fragmentpageadapter就无法识别这个新的fragment。通过channelItem.getNeedUpdate()得到的boolean类型来标识哪个fragment需要更新。
[DEMO下载](http://download.csdn.net/detail/run_forrest_run/9722482)
[DEMO apk下载](http://download.csdn.net/detail/run_forrest_run/9722517)

仿网易腾讯新闻主界面功能相关推荐

  1. 计算机的游戏界面,主界面功能_ 《梦幻西游》电脑版官方网站 - 网易西游题材扛鼎之作...

    主界面功能: <梦幻西游>口袋版中有许多功能和玩法,分布在主界面的不同位置,下面来为大家做一一介绍: 点击主界面左上角人物头像,即可查看角色的个人信息,包括人物属性.召唤兽.装备等等. 在 ...

  2. 071-JAVA项目实训:仿QQ即时通讯软件系列讲座六(讲解QQ主界面功能)

    [上一讲]070-JAVA项目实训:仿QQ即时通讯软件讲座五(讲解用户注册功能)_CSDN专家-赖老师(软件之家)的博客-CSDN博客 [下一讲]072-JAVA项目实训:仿QQ即时通讯软件系列讲座七 ...

  3. android--仿网易新闻主界面

    主要是学习ActionBar+DrawerLayout+ActionBarDrawerToggle,很不错的教程,下面一步一步带你实现这个过程,有不足之处欢迎留言交流. 下面先来一张效果图 根据图片分 ...

  4. 水经微图主界面功能说明

    水经微图主界面简洁大方.操作简单,既符合普通用户的操作习惯,也有适合高级用户需要的专业GIS功能.主界面功能区主要包括用户登录.位置标注.地图绘制.照片管理.CAD制图和系统主菜单等功能项. 用户登录 ...

  5. 出行神器“微图APP”主界面功能概述

    微图的主界面主要包括主菜单功能.搜索定位功能.用户登录.栅格地图切换.矢量图层管理.快速标注.打开3D在线地球.视图显示控制.工具箱.定位到当前位置.视图缩放功能.开启GPS导航.照片拍摄.编辑绘制和 ...

  6. android 网易新闻 登录界面,Android实现仿网易新闻主界面设计

    下面先来一张效果图 根据图片分析,要实现的有侧边栏DrawerLayout,ActionBar的颜色和菜单以及ActionBarDrawerToggle的动画效果. 在这之前,Theme要改成带有Ac ...

  7. 高仿网易评论列表效果之界面分析

    Hello大家好我是周杰伦~!@#¥#@¥%¥%--%&*&--**)--*%&¥%#¥!!!! 不好意思,刚忘了吃药了~~~~扯正事,前几天有个小哥来面试,因为前些天面试了很 ...

  8. Android实战简单新闻主界面设计

    前言 这是自己学习过程单独做出来的,挺适合新手学习,熟悉最基本的banner,imageview,listview,text等等基础控件,适合初学者,原项目共有五个模块,这个是其中一个模块 提示:以下 ...

  9. Android 高仿微信6.0主界面 带你玩转切换图标变色

    目录(?)[+] 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41087219,本文出自:[张鸿洋的博客] 1.概述 学习And ...

最新文章

  1. JS基础-Array对象手册
  2. hdu4885 有 限制的最短路
  3. Oracle 在Sqlplus 执行sql脚本文件。
  4. JPA/Hibernate实体类定义联合主键@IdClass注解的使用
  5. hibernate h2变mysql_懒要懒到底,能自动的就不要手动,Hibernate正向工程完成Oracle数据库到MySql数据库转换(含字段转换、注释)...
  6. 插件开发-UI插件开发
  7. linux rpm yum 安装 软件
  8. c++冒泡排序_python+C、C++混合编程的应用
  9. QCC3005 控制AMP_Mute的管脚配置问题
  10. Android根据经纬度计算距离
  11. Ubuntu16.04 微信网页版安装
  12. 【Harmony OS】【ArkUI】ets开发 基础页面布局与数据连接
  13. BZOJ4340:[BJOI2015]隐身术(后缀数组,ST表,DFS)
  14. 《虎胆龙威5》效果评论
  15. 麦田的守望者背景与分析
  16. 2019下半年阿里面试失败总结
  17. 这个行情,币圈小白该如何生存?
  18. 最小生成树(克鲁斯卡尔算法 普里姆算法)
  19. 建模神器 | 涨知识,BIM渲染神技能
  20. 解决原先mysql与wampserver中mysql冲突问题

热门文章

  1. Dodo:轻量地可定制顶部信息栏
  2. 【Java播放音乐】利用AudioSystem实现音乐的播放、循环播放以及音量的调整
  3. 自动驾驶在中国“不刹停”,北京市给百度颁发了首批路测号牌
  4. 2000年悉尼奥运会歌曲《Under Southern Skies》铃声 2000年悉...
  5. 辉煌优配|热门科技股“一波三折” 三大股指延续分化
  6. Mecanim动画系统 - 使用Blend Trees控制角色动作
  7. Hadoop 入门教程
  8. 简数采集器数据发布到WordPress
  9. 串口服务器控制协议,记录有人物联网USR-W610串口服务器及WEB控制接线图
  10. API自动化测试笔记(一)