使用onConfigurationChanged()手动处理设备方向时,未保存ViewPager选项卡中recyclerview的滚动状态片段 [英] Scroll state of recyclerview inside ViewPager Tab Fragment not saved when device orientation is handled manually using onConfigurationChanged()

查看:55
本文介绍了使用onConfigurationChanged()手动处理设备方向时,未保存ViewPager选项卡中recyclerview的滚动状态片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要实现的目标:

FragmentOne在Tab1下,而FragmentTwoPortrait在Tab2下.我想保存FragmentTwoPortrait的recyclerview的状态,然后还原片段状态以及recyclerview的最后滚动位置.当我将设备从横向旋转到纵向时,也将执行类似的操作.

FragmentOne is under Tab1 and FragmentTwoPortrait is under Tab2. I want to save the state of the recyclerview of FragmentTwoPortrait, then restore the fragment state along with the last scroll position of the recyclerview. Similar operation is intended when I rotate the device from landscape to portrait orientation.

在我这里发布的代码中,通过FragmentTwoLandscape实例进行的Fragment事务在开始时就在FrameLayout内部完成,以创建FragmentTwo的初始状态以进行横向定向.稍后,试图扩大FragmentTwoPortrait的最后保存状态的视图. FrameLayout在纵向方向上是隐藏的,并且仅当设备在横向方向上时才可见.

In my posted code here, Fragment transaction through the instance FragmentTwoLandscape is done inside a FrameLayout at the beginning to create the initial state of FragmentTwo for landscape orientation. Later on, the view of last saved state of FragmentTwoPortrait is tried to be inflated. The FrameLayout is hidden in portrait orientation, and will be visible only when the device is in Landscape orientation.

由于某些原因,我必须通过从父活动内部重写onConfigurationChanged()来手动处理设备方向更改.家长活动的生命周期状态需要在需要时进行相应的处理.

Due to certain reasons, I have to handle the device orientation change manually through overriding onConfigurationChanged() from inside the parent activity. Parent activity's life-cycle states need to be handled accordingly if needed.

最近几天,我尝试了很多解决方案.我已经应用了stackoverflow提供的解决方案,还尝试了一些自己的解决方案.但是似乎没有任何效果!我认为我在某个地方犯了一个愚蠢的错误,使代码无法返回所需的行为.

I have tried out so many solutions over the last few days. I have applied solutions provided on stackoverflow and also tried some of my own. But nothing seems to work! I think I have made a silly mistake somewhere for the code not to return the desired behavior.

附言::在提出解决方案时请牢记: 1.标签片段在viewpager中 2. FragmentTwo不允许调用onSaveInstanceState()[这背后有明显的原因] 3.我无法保留StickyHeaderRecyclerView库的标头值( https://github.com/TellH/RecyclerStickyHeaderView)使用基本的回收站视图方法.

P.S: Please keep in mind while proposing a solution: 1. The tab fragments are inside a viewpager 2. FragmentTwo is not allowed to call onSaveInstanceState() [there are obvious reasons behind that] 3. I cannot preserve the header value of the StickyHeaderRecyclerView library (https://github.com/TellH/RecyclerStickyHeaderView) using basic recycler view methods.

activity_main.xml:

activity_main.xml:

<RelativeLayout 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:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.sakib.viewpagerfragmentrestoration.Activity.MainActivity">

<FrameLayout
    android:background="@android:color/white"
    android:id="@+id/fragment_container"
    android:layout_width="480dp"
    android:layout_height="match_parent"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:visibility="gone"/>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_toStartOf="@+id/fragment_container"
    android:layout_toLeftOf="@+id/fragment_container"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="200dp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            app:tabGravity="fill"
            app:tabMode="fixed"
            app:tabSelectedTextColor="@color/colorAccent"
            app:tabTextColor="#FFF" />


        <com.example.sakib.viewpagerfragmentrestoration.ViewPager.NoScrollViewPager
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>


</LinearLayout>

</RelativeLayout>

MainActivity.java:

MainActivity.java:

public class MainActivity extends AppCompatActivity {

NoScrollViewPager viewPager;
FragmentOne fragmentOne;
FragmentTwo fragmentTwoPortrait, fragmentTwoLandscape;
ViewPagerAdapter adapter;
TabLayout tabLayout;
FrameLayout fragmentTwoLandscapeContainer;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    viewPager = (NoScrollViewPager) findViewById(R.id.pager);
    tabLayout = (TabLayout) findViewById(R.id.tabs);
    fragmentTwoLandscapeContainer = (FrameLayout) findViewById(R.id.fragment_container);

    setViewPagerAdapter();
    loadFragmentForLandscape();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        fragmentTwoLandscape.adjustScrollPosition(fragmentTwoPortrait.getRecyclerView());
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
        fragmentTwoPortrait.adjustScrollPosition(fragmentTwoLandscape.getRecyclerView());
    }

    adapter.notifyDataSetChanged();
    setVisibility(newConfig);
}

private void setVisibility(Configuration newConfig){
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        fragmentTwoLandscapeContainer.setVisibility(View.VISIBLE);
    } else {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
        fragmentTwoLandscapeContainer.setVisibility(View.GONE);
    }
}


private void setViewPagerAdapter() {

    fragmentOne = new FragmentOne();
    fragmentTwoPortrait = new FragmentTwo();

    //Add Fragments to adapter one by one
    adapter = new ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(fragmentOne, "FRAG1");
    adapter.addFragment(fragmentTwoPortrait, "FRAG2");
    viewPager.setAdapter(adapter);
    tabLayout.setupWithViewPager(viewPager);

    if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
        viewPager.setCurrentItem(1);
    }
}


private void loadFragmentForLandscape() {
    fragmentTwoLandscape = new FragmentTwo();

    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.fragment_container, fragmentTwoLandscape);
    ft.commit();
}


// Adapter for the viewpager using FragmentPagerAdapter
class ViewPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();


    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
  }
}

FragmentTwo.java:

FragmentTwo.java:

public class FragmentTwo extends Fragment {
private RecyclerView rv;
private StickyHeaderViewAdapter adapter;
private Random random = new Random(System.currentTimeMillis());

public FragmentTwo() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_two, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    // add your code here which executes after the execution of onCreateView() method.

    initView(view);
    initData();
}

private void initView(View view) {
    rv = (RecyclerView) view.findViewById(R.id.recyclerView);
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
    rv.setLayoutManager(linearLayoutManager);
}


private void initData() {
    Gson gson = new Gson();
    Result result = gson.fromJson(User.dataSource, Result.class);
    List<User> userList = result.getItems();
    Collections.sort(userList, new Comparator<User>() {
        @Override
        public int compare(User o1, User o2) {
            return o1.getLogin().compareToIgnoreCase(o2.getLogin());
        }
    });
    List<DataBean> userListBak = new ArrayList<>();
    String currentPrefix = userList.get(0).getLogin().substring(0, 1).toUpperCase();
    userListBak.add(new ItemHeader(currentPrefix));
    for (User user : userList) {
        if (currentPrefix.compareToIgnoreCase(user.getLogin().substring(0, 1)) == 0)
            userListBak.add(user);
        else {
            currentPrefix = user.getLogin().substring(0, 1).toUpperCase();
            userListBak.add(new ItemHeader(currentPrefix));
            userListBak.add(user);
        }
    }
    adapter = new StickyHeaderViewAdapter(userListBak)
            .RegisterItemType(new UserItemViewBinder())
            .RegisterItemType(new ItemHeaderViewBinder());
    rv.setAdapter(adapter);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_main, menu);
    super.onCreateOptionsMenu(menu,inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_add_view:
            User user = new User("Sticky View", 123, "https://avatars.githubusercontent.com/u/15800681?v=3");
            user.setShouldSticky(random.nextBoolean());
            adapter.append(user);
            break;
        case R.id.action_clear_all:
            adapter.clear(rv);
            break;
        default:
            break;
    }
    return super.onOptionsItemSelected(item);
}


public void adjustScrollPosition(RecyclerView recyclerView) {
    if(recyclerView == null) {
        return;
    }
    LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
    int position = layoutManager.findFirstVisibleItemPosition();
    int positionOffset = (recyclerView.getChildAt(0) == null) ? 0 : (recyclerView.getChildAt(0).getTop() - recyclerView.getChildAt(0).getPaddingTop());

    LinearLayoutManager targetLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
    targetLayoutManager.scrollToPositionWithOffset(position, positionOffset);
}

public RecyclerView getRecyclerView() {
    if(rv == null) {
        return null;
    }
    return rv;
}
}

推荐答案

如果您希望在纵向和横向模式下都具有相同的行为,请尝试不要保存任何配置

If you want same behaviour in both portrait and landscape mode then try not to save any configuration

在AndroidManifest中为此特定活动

In AndroidManifest for this particular activity

android:configChanges="keyboardHidden|orientation"

这篇关于使用onConfigurationChanged()手动处理设备方向时,未保存ViewPager选项卡中recyclerview的滚动状态片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆