像Instagram这样的Android backstack

时间:2017-07-18 20:15:54

标签: android android-navigation

短而简单的版本:我正在尝试像应用程序Instagram一样实现一个Backstack。

他们的导航工作方式

在Instagram中,他们使用底栏中的导航。不知道代码是什么样的。他们创造了一种4车道靠背。

所以我想点击Home(第1道)。然后我设法点击帖子 - >点击用户 - >点击其他帖子 - >最后点击一个标签

然后我在该后巷的后台加了4页。

然后我做了类似于另一条车道的事情(比如帐户页面)。

我知道有2个车道,两个都有4页。如果我在这一点上按回按钮。我只是在打开它们的同一页面上回溯。

但如果我点击返回主页(从底部导航)并从那里点击后退按钮。我会从1号车道而不是2号车道回来。

最大的问题

我如何像堆叠一样实现这条道路?我有没有想到的简单方法?

到目前为止我设法做了什么

我没有成功做很多事情。我创建了一个测试项目,我在这里尝试这种类型的导航。到目前为止,我设法做的就是创建一个包含所有底栏导航页面的大型背板

我对如何实现这种功能的猜测是将背板的一些部分移到顶部并将另一部分向后移动。但这怎么可能?

1 个答案:

答案 0 :(得分:1)

我设法解决了我遇到的问题。不要给我充分的信任。我有一个我看过的参考代码。请查看以下内容。

这可能不是一个可靠的解决方案。但它可能有助于您了解其工作原理背后的逻辑。因此,您可以创建适合您需求的解决方案。

希望这会有所帮助:)

背景我的应用如何运作

首先。我只是想让大家知道我的应用程序是如何工作的。所以你知道为什么我选择了实现这个导航的路线。我有一个活动,保持对它正在使用的所有根片段的引用。该活动一次只添加一个根片段。取决于用户点击的按钮。

当活动创建新的根片段时。它会将它推送到处理它的管理类。

活动本身会覆盖onBackPressed()并调用补充后台堆栈onBackpressed()功能。

活动还会将监听器传递给管理类。此侦听器将告知活动何时关闭应用程序。以及何时刷新当前活动片段

<强> BackStackManager.java

这是管理类。它保留了对所有不同后台堆的参考。它还将任何片段事务职责委托给其FragmentManager类。

public class BackStackManager {

    //region Members
    /** Reference to the made up backstack */
    private final LinkedList<BackStack> mBackStacks;
    /** Reference to listener */
    private final BackStackHelperListener mListener;
    /** Reference to internal fragment manager */
    private final BackStackFragmentManager mFragmentManager;
    //endregion


    //region Constructors
    public BackStackManager(@NonNull final BackStackHelperListener listener,
                            @NonNull final FragmentManager fragmentManager) {
        mBackStacks = new LinkedList<>();
        mListener = listener;
        mFragmentManager = new BackStackFragmentManager(fragmentManager);
    }
    //endregion


    //region Methods


    /** When adding a new root fragment
     * IMPORTANT: Activity his holding the reference to the root. */
    public void addRootFragment(@NonNull final Fragment fragment,
                                final int layoutId) {
        if (!isAdded(fragment)) {
            addRoot(fragment, layoutId);
        }
        else if (isAdded(fragment) && isCurrent(fragment)) {
            refreshCurrentRoot();
        }
        else {
            switchRoot(fragment);
            mFragmentManager.switchFragment(fragment);
        }
    }

    /** When activity is calling onBackPressed */
    public void onBackPressed() {
        final BackStack current = mBackStacks.peekLast();
        final String uuid = current.pop();

        if (uuid == null) {
            removeRoot(current);
        }
        else {
            mFragmentManager.popBackStack(uuid);
        }
    }

    /** Adding child fragment */
    public void addChildFragment(@NonNull final Fragment fragment,
                                 final int layoutId) {

        final String uuid = UUID.randomUUID().toString();
        final BackStack backStack = mBackStacks.peekLast();

        backStack.push(uuid);

        mFragmentManager.addChildFragment(fragment, layoutId, uuid);
    }

    /** Remove root */
    private void removeRoot(@NonNull final BackStack backStack) {
        mBackStacks.remove(backStack);


        //After removing. Call close app listener if the backstack is empty
        if (mBackStacks.isEmpty()) {
            mListener.closeApp();
        }
        //Change root since the old one is out
        else {
            BackStack newRoot = mBackStacks.peekLast();
            mFragmentManager.switchFragment(newRoot.mRootFragment);
        }
    }

    /** Adding root fragment */
    private void addRoot(@NonNull final Fragment fragment, final int layoutId) {

        mFragmentManager.addFragment(fragment, layoutId);

        //Create a new backstack and add it to the list
        final BackStack backStack = new BackStack(fragment);
        mBackStacks.offerLast(backStack);
    }

    /** Switch root internally in the made up backstack */
    private void switchRoot(@NonNull final Fragment fragment) {

        for (int i = 0; i < mBackStacks.size(); i++) {
            BackStack backStack = mBackStacks.get(i);
            if (backStack.mRootFragment == fragment) {
                mBackStacks.remove(i);
                mBackStacks.offerLast(backStack);
                break;
            }
        }
    }

    /** Let listener know to call refresh */
    private void refreshCurrentRoot() {
        mListener.refresh();
    }

    /** Convenience method */
    private boolean isAdded(@NonNull final Fragment fragment) {
        for (BackStack backStack : mBackStacks) {
            if (backStack.mRootFragment == fragment) {
                return true;
            }
        }
        return false;
    }

    /** Convenience method */
    private boolean isCurrent(@NonNull final Fragment fragment) {
        final BackStack backStack = mBackStacks.peekLast();
        return backStack.mRootFragment == fragment;
    }

    //endregion
}

<强> BackStackFragmentManager.java

此类处理所有片段事务。例如添加/删除/隐藏/显示。该类位于BackStackManager类中。

public class BackStackFragmentManager {

    //region Members
    /** Reference to fragment manager */
    private final FragmentManager mFragmentManager;
    /** Last added fragment */
    private Fragment mLastAdded;
    //endregion


    //region Constructors
    public BackStackFragmentManager(@NonNull final FragmentManager fragmentManager) {
        mFragmentManager = fragmentManager;
    }
    //endregion


    //region Methods

    /** Switch root fragment */
    public void switchFragment(@NonNull final Fragment fragment) {
        final FragmentTransaction transaction = mFragmentManager.beginTransaction();

        transaction.show(fragment);
        transaction.hide(mLastAdded);

        transaction.commit();

        mLastAdded = fragment;
    }

    /** Adding child fragment to a root */
    public void addChildFragment(@NonNull final Fragment fragment,
                                 final int layoutId,
                                 @NonNull final String tag) {


        final FragmentTransaction transaction = mFragmentManager.beginTransaction();
        transaction.add(layoutId, fragment, tag);
        transaction.commit();
    }


    /** Add a root fragment */
    public void addFragment(@NonNull Fragment fragment, int layoutId) {
        final FragmentTransaction transaction = mFragmentManager.beginTransaction();

        //since we hide/show. This should only happen initially
        if (!fragment.isAdded()) {
            transaction.add(layoutId, fragment, fragment.getClass().getName());
        }
        else {
            transaction.show(fragment);
        }

        if (mLastAdded != null) {
            transaction.hide(mLastAdded);
        }

        transaction.commit();

        mLastAdded = fragment;
    }

    /** Pop back stack
     * Function is removing childs that is not used!
     */
    public void popBackStack(@NonNull final String tag) {
        final Fragment fragment = mFragmentManager.findFragmentByTag(tag);
        final FragmentTransaction transaction = mFragmentManager.beginTransaction();
        transaction.remove(fragment);
        transaction.commit();
    }

    //endregion
}

<强> BackStack.java

这是一个简单的类,它只处理对root的内部引用和所有backstack子条目的标记。并处理这些子条目

public class BackStack {

    //region Members
    public final Fragment mRootFragment;
    final LinkedList<String> mStackItems;
    //endregion


    //region Constructors
    public BackStack(@NonNull final Fragment rootFragment) {
        mRootFragment = rootFragment;
        mStackItems = new LinkedList<>();
    }

    //endregion


    //region Methods
    public String pop() {
        if (isEmpty()) return null;
        return mStackItems.pop();
    }

    public void push(@NonNull final String id) {
        mStackItems.push(id);
    }


    public boolean isEmpty() {
        return mStackItems.isEmpty();
    }
    //endregion
}

<强>监听

对此没什么好说的。它由活动

实施
public interface BackStackHelperListener {
    /** Let the listener know that the app should close. The backstack is depleted */
    void closeApp();

    /** Let the listener know that the user clicked on an already main root. So app can do
     * a secondary action if needed
     */
    void refresh();

}

<强>参考

https://blog.f22labs.com/instagram-like-bottom-tab-fragment-transaction-android-389976fb8759