使用ViewPager时,如何对view进行更新

ViewPager是个好东西,但往往有些业务需要是android无法满足的,比如要更新ViewPager的特定view


本帖其实就是StackOverflow的总结帖

原帖见http://stackoverflow.com/questions/7263291/viewpager-pageradapter-not-updating-the-view


一种简单快速的办法:

Override getItemPosition in your PagerAdapter like this:

public int getItemPosition(Object object) {
    return POSITION_NONE;
}
This way, when you call notifyDataSetChanged(), the view pager will be updated.

这种方法其实就是将制定位置的item给destroy掉,然后重新创建一个新的,很暴力。某大牛写到

I think that there is no any kind of bug in the PagerAdapter, the problem is that its understanding is a little complex. Looking the solutions explained here, there is a misunderstanding and then a poor usage of instantiated views from my point of view.

I have been working the last few days with PagerAdapter and ViewPager, and i found the following:

The notifyDataSetChanged() method on the PagerAdapter will only notify the ViewPager that the underlying pages have changed. For example, if you have create/deleted dynamically pages (adding or removing items from your list) the ViewPager should take care about that. In this case i think that the ViewPager determines if a new view should be deleted or instantiated using the getItemPosition() and getCount() methods.

I think that ViewPager after a notifyDataSetChanged() call, takes its child views, and check their position with the getItemPosition(). If for a child view this method returns POSITION_NONE, the ViewPager understand that the view has been deleted, calling the destroyItem(), and removing this view.

In this way, overriding the getItemPosition() to return always POSITION_NONE is completely wrong only if you want to update the content of the pages. Because the previously created views will be destroyed, and a new ones will be created every time you call notifyDatasetChanged(). It may seem to be not so wrong just for a few TextViews, but when you have complex views, like ListViews populated with databases, this may be a real problem and a waste of resources.

So there are several approaches to efficiently change the content of a view without having to remove and instantiate again the view. It the depends on the problem you want to solve. My approach is to use the setTag() method for any instantiated view in the instantiateItem() method. So when you want to change the data or invalidate the view that you need, you can call the findViewWithTag() method on the viewPager to retrieve the previously instantiated view and modify/use it as you want without having to delete create any new view each time you want to update some value.

Imagine for example that you have 100 pages with 100 TextViews and you want to update only one value periodically.. with the approaches explained before it will means to remove and instantiates 100 TextView in each update. It does not make sense...


Good! 是个很好的思路,对PagerAdapter的行为做手脚,来实现我们想要的效果。

文中提到在 instantiateItem(ViewGroup container, int position) 时,进行setTag(),然后在需要更新的view的地方,使用findViewWithTag (Object tag)获取到要操作的view,直接操作这个view即可。


但是PagerAdapter的instantiateItem方法写到

Create the page for the given position. The adapter is responsible for adding the view to the container given here, although it only must ensure this is done by the time it returns from finishUpdate(ViewGroup).
所以覆盖 instantiateItem是不保险的,因为这时候view可能并未被创建,而在finishUpdate()时是确保view可用的。

大致的顺序

1.PagerAdapter.instantiateItem()

2.FragmentPagerAdapter.getItem()  -- 这时并没有创建fragment的view

3.FragmentManager.moveToState() -- 这里调用了fragment的onCreateView()

4.PagerAdapter.finishUpdate()





Android Studio中使用ViewPager和BottomNavigationView,你可以按照以下步骤进行操作: 1. 首先,在你的XML布局文件中添加一个ViewPager和一个BottomNavigationView。例如,你可以在LinearLayout中添加一个ViewPager和一个BottomNavigationView,如下所示: ``` <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.viewpager.widget.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottomNavigationView" android:layout_width="match_parent" android:layout_height="wrap_content" app:menu="@menu/bottom_nav_menu" /> </LinearLayout> ``` 2. 创建一个PagerAdapter来管理ViewPager的页面。你可以创建一个继承自FragmentPagerAdapter或FragmentStatePagerAdapter的类,并实现相应的方法。这些方法包括getItem()方法,用于返回ViewPager中的Fragment实例,以及getCount()方法,用于返回ViewPager中的页面数量。 3. 在MainActivity或相应的Activity中,将ViewPager与PagerAdapter关联起来,并设置ViewPager作为BottomNavigationView的监听器。在ViewPager的onPageSelected()方法中,你可以根据选中的页面来更新BottomNavigationView的选中项。 ``` ViewPager viewPager = findViewById(R.id.viewPager); viewPager.setAdapter(new YourPagerAdapter(getSupportFragmentManager())); BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView); bottomNavigationView.setOnNavigationItemSelectedListener(item -> { switch (item.getItemId()) { case R.id.menu_item1: viewPager.setCurrentItem(0); return true; case R.id.menu_item2: viewPager.setCurrentItem(1); return true; case R.id.menu_item3: viewPager.setCurrentItem(2); return true; } return false; }); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { switch (position) { case 0: bottomNavigationView.setSelectedItemId(R.id.menu_item1); break; case 1: bottomNavigationView.setSelectedItemId(R.id.menu_item2); break; case 2: bottomNavigationView.setSelectedItemId(R.id.menu_item3); break; } } @Override public void onPageScrollStateChanged(int state) { } }); ``` 4. 创建相应的Fragment用于显示ViewPager中的页面。你可以创建继承自Fragment的类,并在PagerAdapter的getItem()方法中返回这些Fragment的实例。每个Fragment将显示不同的内容。 通过按照以上步骤,在Android Studio中使用ViewPager和BottomNavigationView来实现底部导航栏同步切换操作。记得在布局文件中添加菜单文件(即bottom_nav_menu.xml),并在代码中设置相应的选中项和页面切换逻辑。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值