仿网易腾讯新闻主界面功能
来源:互联网 发布:淘宝客api2.0接入流程 编辑:程序博客网 时间:2024/04/29 12:09
最近项目中有一个需求,类似网易、腾讯新闻客户端的频道管理界面,可以对频道进行排序、增加、删除功能。网上也找了相关的资料,但是发现他们都有同一个问题,就是改变频道的顺序后,对应频道的内容并不会改变。这是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; @Override protected 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加载viewpager mNewsTab.setupWithViewPager(mNewsVp); } private void intData() { for (ChannelItem channelItem : mUserChannelList) { NewsFragment newsFragment = new NewsFragment(); Bundle bundle = new Bundle(); //设置tag,区分不同频道的Fragment bundle.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())); } } @Override public void onClick(View v) { //打开频道管理Activity Intent intent_channel = new Intent(this, ChannelActivity.class); startActivityForResult(intent_channel, CHANNELRESULT); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case CHANNELRESULT: //频道发生改变后,重新设置Fragment if(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; @Override protected 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)); } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub if (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点击监听接口 */ @Override public 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() { @Override public void onAnimationStart(Animation animation) { isMove = true; } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { moveViewGroup.removeView(mMoveView); // instanceof 方法判断2边实例是不是一样,判断点击的是DragGrid还是OtherGridView if (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()); } @Override public 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; } @Override public boolean onDown(MotionEvent e) { // TODO Auto-generated method stub return false; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub return false; } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public 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; } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub } @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return 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(); } @Override public int getCount() { return list_fragment.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } //此方法用来显示tab上的名字 @Override public CharSequence getPageTitle(int position) { return channelItems.get(position).getName(); } int count; @Override public Fragment getItem(int position) { return list_fragment.get(position); } @Override public Object instantiateItem(ViewGroup container, int position) { if (!integers.contains(position)) {//如果这个positionFragment上的没有被初始化,就把这个position添加到集合中 integers.add(position); } //得到缓存的fragment NewsFragment 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); //移除旧的fragment itemFragment = (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 0
- 仿网易腾讯新闻主界面功能
- Android应用经典主界面框架之二:仿网易新闻客户端、CSDN 客户端 (Fragment ViewPager)
- Android应用经典主界面框架之二:仿网易新闻客户端、CSDN 客户端 (Fragment ViewPager)
- Android应用经典主界面框架之二:仿网易新闻客户端、CSDN 客户端 (Fragment ViewPager)
- Android应用经典主界面框架之二:仿网易新闻客户端、CSDN 客户端 (Fragment ViewPager)
- Android应用经典主界面框架之二:仿网易新闻客户端、CSDN 客户端 (Fragment ViewPager)
- Android应用经典主界面框架之二:仿网易新闻客户端、CSDN 客户端 (Fragment ViewPager)
- 仿网易新闻主界面(一)——RadioGroup+Fragment
- 仿网易新闻主界面(二)——TabLayout+ViewPager
- 使用TabLayout+ViewPager+Fragment+DataBing实现仿网易新闻主界面效果
- iOS界面-仿网易新闻左侧抽屉式交互
- iOS界面-仿网易新闻左侧抽屉式交互
- iOS界面-仿网易新闻左侧抽屉式交互
- iOS界面-仿网易新闻左侧抽屉式交互
- iOS界面-仿网易新闻左侧抽屉式交互
- iOS界面-仿网易新闻左侧抽屉式交互
- iOS界面-仿网易新闻左侧抽屉式交互
- iOS界面-仿网易新闻左侧抽屉式交互
- plsql 安装后database下拉没有东西
- 动态规划---走格子
- Linux的经典文本编辑器vi的使用, 基本的文件内容查看命令
- 百度Ueditor编辑器的Html模式自动替换样式的解决方法
- js作用域链
- 仿网易腾讯新闻主界面功能
- Android开发中Progress需要两边都是圆角怎么办?
- 阻止事件冒泡
- Android Studio获取MD5和SHA1值(应用签名)
- 硬盘参数 PIO/DMA/UDMA/SWDMA/MWDMA
- androoid framework学习之Service组件
- 大型项目中的敏捷项目管理实践
- 为什么要设堆区和栈区
- ZooKeeper 安装部署及hello world