I have seen this pattern on both Tumblr and Telegram apps.
When you are in a detail view (Searching for a Hashtag on Tumblr or in a conversation on Telegram) and swipe from left to right (like if you were going to pull a Navigation Drawer) you can see the previous activity come up from there. If you release it, the Activity is finished.
How is this behavior implemented?
[Disclaimer: the following dissertation was written after just one hour or so examining Telegram's source code, so it may contain important flaws or mistakes. Feel free to comment]
The case of Telegram looks to be quite different from what Teovald says. In Telegram's case it is not a fixed image. You can check this by having for instance an open chat where someone is writing half swiped. You will see that both the "chat activity" and the "list of chats activity" are updated in real time, which could not be the case if the effect were accomplished by using a static image.
Since Telegram is open sourced, you can have a look at its code base to figure out how it is actually done.
After examining the code myself for a while, it looks like what they do is not a visual trick. In fact, its a trick which goes far beyond doing small trickery to fake some visual effect. Whatever the case, it smells like some non-standard stuff.
First of all, you can have a look at Telegram's manifest file to see that they only define three activities (LaunchActivity, IntroActivity and PopupNotificationActivity)... three activities! Anyone using Telegram would agree that the application seems to have more than three activities, so whatever they are doing it looks like in practice they only have a single activity running at the same time (LaunchActivity), which through some mechanism shows different "activity like" content.
Indeed, if you go to LaunchActivity you will see that it inherits from a so called ActionBarActivity, which would be the base class for all real activities in Telegram (although in practice only LaunchActivity seems to extend it). This activity seems to take care of implementing, along with other classes, the action bar. Yes, that means that Telegram does not use the standard action bar, nor defines any kind of wrapper to use a "mock" version on Android < 11 and the real version on Android >= 11. It's quite twisted, but you can have a look at their implementation of the action bar (class ActionBar as well as other dependent classes) and see that they are literally creating a raw FrameLayout and embedding it to emulate the action bar. This means, among other things, that they do not inflate XML resources to define the action bar for each "activity", they populate it by hand instead. Very cumbersome and very non-standard, which in my opinion makes Telegram kind of weak regarding improvements of the action bar in future versions of Android.
Now, the thing that concerns me the most is that they are completely ignoring the Android's activities and fragments system, rolling out their own version. To be precise it's not like they are ignoring Android's activities and fragments altogether, but they are using some techniques that (in my humble opinion) would be frowned upon by probably most of Android developers out there.
If you look at ActionBarActivity you will see that it extends a regular Android Activity. It removes (via its theme, and also programatically) the standard action bar and title of the activity in the onCreate() method (this confirms that they use their own customized version of the action bar). But most importantly, they define a "stack" of "fragments". A "fragment" here is not what one understands by "Android fragment", but some weird version they rolled out too to implement the concept of "fragment". They use the BaseFragment class to define a "fragment", which is basically a class that creates its view via a callback (just as Android's fragments do), and which defines some "life cycle" methods such as onPause() and onFragmentDestroy(). Then you can see that what we would consider to be regular Android activities is actually implemented via this weird mechanism of BaseFragments. For instance, the "chat activity" is implemented by the ChatActivity class, however this does not inherit from Android's Activity, but from BaseFragment instead.
So to summarize what I have explained so far, Telegram seems to be an application running a single activity (LaunchActivity, which in turn inherits from ActionBarActivity), which implements a customized action bar and a weird "fragment" framework which emulates regular Android activities, at least at the visual level.
Now, if you look at the onTouchEvent() method of the ActionBarActivity class, this seems to be the one in charge of implementing the core algorithm of the "swipe to dismiss" effect. This tracks the user's finger and moves the view of the fake fragment accordingly. When the user lifts the finger, if the condition to dismiss the "fragment" is true (backAnimation is false), the fragment is removed: when the animation ends, the onSlideAnimationEnd() method is called, which will then remove the "fragment" from the fragment stack kept by the ActionBarActivity class.
So, in short, Telegram accomplishes the "swipe to dismiss" effect by implementing a funky "fragments" system in which what seems to be an Activity is a raw view modeled via a subclass of BaseFragment. This forces them to roll out their own version of the action bar, and also to follow some very weird and "non-standard" Android techniques.
I did not actually know that Telegram was implemented this way, so at this moment I am kind of disappointed. I was expecting them to access some hidden Android APIs, which of course would be wrong, but at least it would not be so cumbersome and ugly as implementing their own action bar and "fragments" system. From now on, to me, Telegram's code will be a reference of what you must not ever do in Android.
Like any good visual feature, it is a trick :-) .
If you use the UI Automator tool to dump the screen content while in a middle of one of these back slides, you can see that the 'old fragment' is in fact just an image view.
It is only when the slide is finished that the previous fragment/activity is brought from the back stack.
I have just implemented this, check it out here
SwipeFinishableActivity.
Generally speaking, you need a translucent top activity so that when you drag the top activity you can see the second top one below. And you should track your touch event to move your views in your activities.
Related
I am working on an application that has several states that matter to the user, online vs offline, how far out of date the local application database is, et cetera. I understand that both non-persistent and persistent notifications are available in android, and might be appropriate in this scenario. However, in our organization's iOS application, there is an 'information bar'.
I realize that this is somewhat of a departure from material design. Is this even possible? I'd like to extend the App Bar in some way as opposed to creating a fragment that I add to every activity if possible.
Try any of the following
1) Replace the action bar with toolbar and customize the design on your own and handle it.
2) Create the separate layout file with the above design and then include it in any screen using the tag <include/>
You can do this a custom Toolbar class or with Fragments. For the later option, each activity will have the user information at the top, either as a view or a fragment. The "normal app stuff" will be a FrameLayout which can hold one fragment at a time. See the Fragment tutorials on http://developer.android.com.
There aren't really hooks for extending the toolbar- in fact Google has deprecated a lot of stuff it used to be able to do (such as tabs in the toolbar). Your best bet is to use a custom fragment at the top of every Activity.
I've recently been looking into the navigation system that Android uses with as intention to port my iOS app that uses an UITabBarController containing multiple UINavigationControllers. To replace the tab bar (which is not available on Android) I settled on using the built in DrawerLayout.
From what I've read, navigation in Android is generally done by creating an Intent, providing it with extras and then just replacing the current activity. This automatically makes sure the back button works, and optionally the back button in the top left if enabled.
However, I am not sure how to implement this way of navigation with the navigation drawer. The tutorial tells me to create a DrawerLayout containing a FrameLayout and a ListLayout where the FrameLayout will contain the actual application and the ListLayout will contain the navigation. This would mean that when I use the method described above to "navigate", it would replace the activity and thus removing the drawer.
What would be the best way to implement what I want (basic navigation with back button support while maintaining a global drawer navigation menu)? The possible options I can come up with is always keeping the same activity and dynamically replacing the FrameLayout, but that would mean a lot of boilerplate to render and possibly a hack to support the back button (and there would be no animations :(). The other option would be to just render the drawer on every activity (via subclassing or something), but that would mean that if the user navigates a lot the back button "stack" would become quite large.
I have tried to explain what I need in as much detail as possible, but it is quite hard to explain the concept. Basically, I want something similar to the UINavigationControllers in the UITabBarController.
You can either have one Activity with one NavigationDrawer and present the user with different views by switching Fragments back and forth within that one Activity. You would use the FragmentManager to switch between different Fragments.
Or you can use multiple Activities that all have a NavigationDrawer.
Second option might sound more difficult but it really isn't. You create a base Activity that all your Activities inherit from and all let them have their own NavigationDrawer, no problem.
Sure there's something in between or something completely different, but that's the most straightforward approaches I can think of.
The tutorial you've probably used (the one with the planets) is imho a bit misleading because it assumes a very basic app structure. If you have only little different 'screens' that might work, for a very complex application it's not suitable (again, in my opinion).
I've always opted for the second option because handling the navigation / backstack is just easier with Activities / Intents.
There's loads of different flags that you can set to your Intent to influence their navigation behaviour.
Also see this and that documentation. These documents might have been written when the NavigationDrawer pattern was not all that common but they are still useful.
There are few similar questions on stackoverlow, but I haven't find clear explanation at any of the answers how to implement Action Bar pattern for more complex/multiple activities apps.
As I understand, there are two options to do this:
1.) implement multiple activities and in each of them implement/include action bar
--> problem with this is that when ever you lunch new activity, although it has the same looking action bar, it has that transition, and jumps through the screen, so it's obvious it's a new "window",new separate screen, and it kills that feeling of single app navigation frame.
2.) Use single FragmentActivity, with action bar within, and with multiple fragments that inflate content frame.
--> this is pretty nice implementation of action bar pattern, but problem is that it goes against google's recommendation that one fragment should be in one activity in the case of phone. Or it doesn't? From the "look and feel" I would say that Gmail app is done mostly this way.
3.) TabActivity - which is deprecated.
For the second solution (single activity, multiple fragments) I'm concerned if there would be any performance issue in the future? How does android handle memory in that case? will it kill inactive fragments to free space just like it does with the activities? Or it will kill the whole app, or user phone will be overloaded?
Maybe I'm missing something there, but I found implementing android navigation patterns and usage of fragments very confusing :/
Is there any reason against having one activity with multiple fragments on the phone?
(there would be cca 5-6 fragments, with nested fragments in some of them)
First of all, you might think this question and this answer to be useful.
Though you are talking about the actionbar, the real question is about the pattern of ONE activity with multiple fragments or MULTIPLE activities. As the former link states, though the "oversimplified tutorial" suggests of starting another activity to display item's content in Phone situation, this will probably cause some duplicated logic or codes.
Finally, using "FragmentActivity with multiple fragments" is recommended. As it is against the the google's recommendation, Stephen Asherson says and I quote: " do not think of it as being forced to use many activities. Think of it as having the opportunity to split your code into many fragments, and saving memory when using them".
PS. just for your information, if you change the activity's actionbar in switching fragments, you might want to do something to correctly handle the UI change when "back" key is pressed and backstack is changed. Commonly, override the onbackstackchanged() function to handle the UI.
I have seen a few questions raised on this topic (for e.g.: https://github.com/jfeinstein10/SlidingMenu/issues/5) but I am still unclear. I hope somebody can clarify this.
Context:
See https://github.com/jfeinstein10/SlidingMenu
I have an android app that organizes screens by activities and fragments (i.e.) each screen is an activity containing one or more fragments.
The new requirement is to add a sliding menu (similar to what this library provides).
Issue:
It appears from the examples and discussion that the right model would be to have just 1 MAIN ACTIVITY that will then switch in/out fragments belonging to the different screens. In fact the author mentions in the above thread: "If you were to launch Activities based upon the list selection, then you would not have the behavior where you swap the views that you're talking about. " and also "You can't put an Activity into the above view. That doesn't really make sense when you think about what an Activity is. ".
Why doesn't it make sense? Obviously, I am missing the point here.
Question:
Given that my project already contains multiple activities (one corresponding to each screen), is my only option then to re-organize the project to have JUST 1 MAIN ACTIVITY, in order to use this library? Or alternatively, is there any way to launch a new activity when a list item in the sliding menu is clicked, and still observe the sliding menu behavior, [EDIT- added the last part to be more clear] or in other words, on how exactly to use this library within my existing app design.
Thanks in advance
First, you can't have an Activity inside another and activities are completely different from views as stated in the docs:
An activity is a single, focused thing that the user can do.
Now, to answer your question, it all depends on how you want your app to behave. You could have your activities with the sliding menu implement the onClosedListener and switch to the selected activity from there. This will give you the animation of closing the menu before switching activities. It will also give you a weird effect since every time you select something from your menu you'll see the animation of a new activity coming to the front.
I think the best approach would be to have a "common purpose" between all your sliding menu options. For example, in one of my projects I have to allow the users to select between lists of different types of data. When the user selects anything from the menu, I load a new list fragment into the right corner where he may choose the item he wants to view or edit. That's the app entry point and also the only place were I have a sliding menu in my app. It is pretty much the same for every app that implements this UI design pattern. Look at google+, currents and youtube where the side menu lets you choose which feed or content to show. Once a user makes a selection, just open a new activity for the selected item (a g+ post, a video, a news article, a tweet or whatever it is).
Your app doesn't have to have lists of different data or anything like that to use the sliding menu, but keep in mind that the activity with the sliding menu should have a clear, focused goal with respect to its functionality and purpose. Having a sliding menu because many other apps have one is a bad choice, you should use it with a specific objective. Also keep in mind that applying the sliding menu everywhere would interfere with the platform's navigation pattern and lead to an overall bad user experience since it wouldn't behave as the other apps.
It doesn't make sense to place an Activity into the above view because the Activity is the main controller for the view of each screen. The Activity also shows views and keeps track of Fragments (which in turn are mini controllers, with or without their own views). So placing an Activity in the above view would mean that you would place an Activity in an Activity... Wich is impossible.
From what I can derive from your text I think it would be wise to read through the Android developer guide on Activities and Fragment again (http://developer.android.com/guide/components/activities.html) to get a better understanding of how the concept of Android works.
Now to your question:
I am not clear on what you are trying to achieve but if you want your app, with menu to behave like, say, the Google+ app then one way of doing it is to implement a base class that extends the Activity class (or what ever base Activity used in your project) and let the base set the SlidingMenu. Then you would simple extend your base Activity in each of the Activities that are supposed to have a menu.
You could also do it the way you describe it, but then you would end up with a classic example of a God object (http://en.wikipedia.org/wiki/God_object). It's a neat way to practice your Fragment juggling skills and switching between Fragments instead of starting new Activities does have it's use cases, but I still wouldn't recommend it for a project with more then a few views.
Here is the answer that came closest to the issue I had - http://www.verious.com/article/polishing-the-sliding-app-menu/. Scroll down to the bottom of the page to see the last section titled "Using the fly-in app menu between Activities". This is one option if you have a lot of activities in your existing app and want to avoid extensive re-factoring. I haven't tried this out yet but its worth being aware of.
I am playing around with controlling the UI Navigation buttons in ICS.
The current mechanism for suppressing the Nav Buttons is to call setSystemUiVisibility from a View using the SYSTEM_UI_FLAG_HIDE_NAVIGATION or SYSTEM_UI_FLAG_LOW_PROFILE flags. This seems like a strange place for setting these flags, as most other related settings (such as hiding the status bar) have been done through window LayoutParams properties.
My question is if any of you have ideas for a good way to do it from an Activity context. Currently my app is designed to start with a base activity class which contains any functionality I want throughout my entire application. Specific Activities are then derived from that base class. I would like to be able to set the UI nav flags from that base Activity so I don't have to do it in multiple spots throughout my source code... but my base Activity does not contain any View objects.
As a secondary statement, what I would really like to be able to do is completely remove the NAV buttons (such as using SYSTEM_UI_FLAG_HIDE_NAVIGATION) and not have them come back on user input (giving my app complete control over the UI). I know this is not something that any app from the market should be able to do... but I am not developing something that will available via the market. My current plan involves a custom build of the OS that will allow me to accomplish this, but it would be nice if there was some method of eliminating those soft buttons in the meantime.
Thanks!
This is what I put in onCreate of my activities:
View main_layout = dialog.findViewById(android.R.id.content).getRootView();
main_layout.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
It's almost like calling it from an activity context. At least it's not dependent on having a view defined at compile time. I know STATUS_BAR_HIDDEN is deprecated, but I can't get SYSTEM_UI_FLAG_LOW_PROFILE to compile at the moment...
But +1 on the "this seems like a strange place for these settings". Should be something you can define in the manifest once for the entire app.
You can't completely remove the ICS navigation buttons.
You can hide them completely, but they'll reappear as soon as you touch the screen:
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
Unfortunately, some ICS UI layers like Samsung's TouchWiz won't recognize SYSTEM_UI_FLAG_HIDE_NAVIGATION.
Alternatively, you can minimize them and they'll only appear when the bar it tapped:
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
You'll probably have to build your own ROM to eliminate them completely.