Comments (6)
There are multiple ways to go about it, but you are right, I should add an example for this.
The two ways I can think of:
The root view (which is bound to the key that is the top new state) manages the existence of the nested views that can exist inside it by inflating them with LayoutInflater.from(new KeyContextWrapper(getContext(), nestedKey)).inflate(R.layout.nested_view, this, false);
in order for them to have their own key.
There are two ways that state persistence can be handled.
1.) the root view manages the state of its children through collecting them into the bundle provided by Bundleable
, and they are restored from that bundle.
2.) each child is able to write into BackstackDelegate.persistViewToState(this);
, but by default behavior BackstackDelegate.clearStatesNotIn()
clears all keys that are not in the new state of the backstack (stateChange.getNewState()
), therefore to preserve children of a composite key, one must be able to obtain what keys exist on top of what is inside the backstack itself; and redefine backstackDelegate.clearStatesNotIn()
to keep those states as well.
Previously I've been using approach 1 (which takes a bit of boilerplate but it works), but I'm also working on making it possible with approach 2 without having to explicitly redefine clearStatesNotIn()
as user of the library.
Child keys and Composite keys are on the roadmap; I'm in the process of figuring them out ( see here where I'm experimenting with the how).
In the meantime, I can show you a pager adapter for ViewPager that can store the state of its children:
public abstract class ViewPagerAdapter
extends PagerAdapter {
final Bundle[] bundles = new Bundle[getCount()];
final View[] views = new View[getCount()];
@Override
public View instantiateItem(ViewGroup container, int position) {
View view = getItem(position);
if(bundles[position] != null) {
Bundle savedState = bundles[position];
view.restoreHierarchyState(savedState.getSparseParcelableArray("viewState"));
if(view instanceof Bundleable) {
((Bundleable) view).fromBundle(savedState.getBundle("bundle"));
}
}
container.addView(view);
views[position] = view;
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View)object;
if(bundles[position] == null) {
bundles[position] = new Bundle();
}
Bundle savedState = bundles[position];
saveStateForView(view, savedState);
views[position] = null;
container.removeView(view);
}
@Override
public Parcelable saveState() {
Bundle pagerState = new Bundle();
for(int i = 0; i < getCount(); i++) {
if(views[i] != null) {
if(bundles[i] == null) {
bundles[i] = new Bundle();
}
View view = views[i];
Bundle savedState = bundles[i];
saveStateForView(view, savedState);
}
if(bundles[i] != null) {
Bundle viewState = bundles[i];
pagerState.putBundle("viewState_" + i, viewState);
}
}
return pagerState;
}
private void saveStateForView(View view, Bundle savedState) {
SparseArray<Parcelable> viewState = new SparseArray<>();
view.saveHierarchyState(viewState);
savedState.putSparseParcelableArray("viewState", viewState);
if(view instanceof Bundleable) {
savedState.putBundle("bundle", ((Bundleable) view).toBundle());
}
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
Bundle pagerState = (Bundle)state;
pagerState.setClassLoader(loader); // added to fix BadParcelException on process death
for(int i = 0; i < getCount(); i++) {
Bundle viewState = pagerState.getBundle("viewState_" + i);
if(viewState != null) {
bundles[i] = viewState;
}
}
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
public abstract View getItem(int position);
}
Now if clearStatesNotIn()
is overridden, then the Bundle
and SparseArray
you see here can be replaced with backtackDelegate.getSavedState(key)
, if getItem()
returns a view that is associated with its own key.
Otherwise, PagerState
preserves it into root key's SavedState.
With current default setup, you can use Bundleable
to save state into parent view's bundle. That's what I've been doing.
from simple-stack.
@blackkara the latest update v1.1.1 also includes simple-stack-example-multistack
which shows how to use Simple-Stack with multiple backstack per each tab on a bottom nav view in one activity.
from simple-stack.
I will close this for now, I've answered the question: the parent must handle the state management of their children. Whether you use a Backstack
instance and register the custom view as a StateChanger
is up to you.
This is improved upon when composite keys are introduced, tracked in #12.
Another similar use-case will be covered by #13.
from simple-stack.
Firstly thanks and then sorry for my lated reaction. Your comments (pager adapter way) and multistack example work like a charm ! I implemented them on different sample projects individually to get idea and difference.
Actually i had tried the pager adapter way before the latest multistack example already. So,
- Activity layout contains only
RelativeLayout
(root) - Created custom view (say SkeletonView) that includes bottom navigation.
- Created other custom views (say AView, BView, CView) for bottom navigation in SkeletonView
- Inflated SkeletonView and added to root (And inflated A,B,C views)
- And then created a new custom view to replace with SkeletonView.
You can think the last step like, i wanna go to a screen that doesn't have bottom navigation (maybe about page) So i did all of them with help of your first comment.
But, multistack example doesn't allow this navigation technically, Because activity layout has already structure including bottom navigation. And the root view in it, services for only tabs. Now i'm converting the multistack example for my scenario
from simple-stack.
@blackkara actually, your concern is legitimate - if you separate the bottom navigation into 4 different stacks, then you pretty much can't swap out the "main view" as a viewgroup, because the scope of the bottom navigation becomes bound to the Activity instance.
So the multi-stack example is more-so for when you have to keep 4 separate tabs up and can navigate between them at any time.
I can barely wait to finish 2.0 which will bring Composite Keys and a local backstack for each view associated with a key.
from simple-stack.
Along with the view-pager example shown above, another possibility is to use service-tree
to provide managed services for the given keys (so that they survive configuration change and depend on the simple-stack history instead), allowing BackstackManager
to be created and used per view.
Now with 1.3.0, an example called simple-stack-example-nestedstack
is added for a setup for this particular type of complex nesting.
from simple-stack.
Related Issues (20)
- Allow removing a `Backstack.CompletionListener` from inside the listener itself HOT 5
- Clarification: can a service be registered/unregistered more than once? HOT 5
- Can I Use @styles/Theme.MyComposeTheme on AndroidManifests.xml? HOT 3
- Question: What is the purpose of RegistrationViewModel inside ServiceProvider in extension-compose-example? HOT 4
- What is the proper way to add a key to the top even if it already exists in the backstack? HOT 2
- Publish to MavenCentral instead of just Jitpack.io
- Unable to start activity ComponentInfo{com.xxxxxxxxxx.yyyyyy/com.xxxxxxxxxx.yyyyyy.activities.MainActivity}: androidx.fragment.app.Fragment$InstantiationException: Unable to instantiate fragment q2.v1: could not find Fragment constructor HOT 7
- How to 'lookup<>()' scoped class from an Android Service HOT 2
- Lazy initialization of ScopedServices HOT 2
- KMM support? HOT 2
- Screen can get the service from wrong scope during back animation HOT 6
- Backstack is not available in a child Fragment's onCreate after process death
- DialogFragment and BottomDialogFragment as part of navigation stack, question HOT 2
- Verify that the new `setParentServices()`'s `lookupFromScope(..., EXPLICIT)` behavior is what is expected
- Updating the Compose example to Compose 1.5.0 requires AGP 8.1
- Should Simple Stack be used in new projects HOT 14
- Crash due to activity.onBackPressed() when removing fragment hosting a WebView in AndroidView {} + FADE HOT 15
- Backstack with espresso HOT 3
- The service does not exist in any accessible scopes HOT 11
- Up navigation examples are hard to find HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from simple-stack.