When transitioning between pages, each fragment page shares the same menu options. The menu option contains button which launches an activity. That activity is highly dependent on the information the current page item shows.
I noticed that when I change the view such that, the next page is almost shown on the screen (not fully transitioned) and I select the option for that item, the options shows the data from the previous item. I think this is because, he transition between pages was not fully complete. This is kind of confusing for my users. There could be people who swipe faster and press the option button. I noticed then when swiping between fragments and then suddenly press the menu option. The options shows the data from the previously active page.
If I could only hide the menu options, and only show it when the page is fully transitioned, I believe I can solve this problem. Or else, maybe I am doing something wrong which could have averted this in the first place?
I am using FragmentStatePagerAdapter.
Thank you!
Use ViewPager.SimpleOnPageChangeListener and when the onPageScrollStateChanged event is triggered check to see the state of the scroll if is idle then the page is in view and active (allow user to press the menu button), if is in another state then lock/hide the menu buttons.
I think I was able to solve my problem. I created an interface on my fragment which the hosting activity has to implement:
public interface OnOptionsMenuEnabledListener{ public boolean onOptionsMenuEnabledListener(); }
The hosting activity will just return a flag indicating if the menu is enabled.
#Override
public boolean onOptionsMenuEnabledListener()
{
return mOptionsEnabled;
}
And set the flag via ViewPager.onPageScrollStateChanged (int state):
#Override
public void onPageScrollStateChanged(int state)
{
switch(state)
{
case ViewPager.SCROLL_STATE_IDLE:
mOptionsEnabled = true;
break;
case ViewPager.SCROLL_STATE_DRAGGING:
mOptionsEnabled = false;
break;
case ViewPager.SCROLL_STATE_SETTLING:
mOptionsEnabled = true;
break;
}
}
Every time the option is being selected during screen transition, I call the interface method to communicate to me what the status of the flag:
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
boolean enable = true;
if(mOnOptionsMenuEnabledListener != null)
{
enable = mOnOptionsMenuEnabledListener.onOptionsMenuEnabledListener();
}
if(enable)
{
...
// select your menu items
}
return true;
}
So in this approach, the menu is still there (which is a big plus). But the option menu doesn't react until it settles down on a particular page.
With this I no longer encounter the problem.
I hope this help someone in the future!
Cheers!
When the button is clicked check ViewPagers current item -
https://developer.android.com/reference/android/support/v4/view/ViewPager.html#getCurrentItem()
YourObject object = yourList.get(yourViewPager.getCurrentItem());
Related
I have 4 tabs in my app. In which one is accessible without log-in but others can't be. So, I need to implement a functionality in which if a user clicks on that tab then rest 4 will be disabled and when I click on those tabs I only want toast but if I click on those tabs I get toast but it also got selected but fragment not changed. I want to disable that tab
I have assigned a value to a variable to check whether it is without logging or after logging.
Code:
case R.id.home:
if(value.equals("1")){
Toast.makeText(CarerSeekerActivity.this,R.string.login_signup,Toast.LENGTH_SHORT).show();
navigation.getMenu().getItem(0).setEnabled(false);
}
else {
fragment = new CreatePersonalizedPackageCareSeekerFragment();
changeFragments(fragment);
}
return true;
but it is showing toast and but selected that tab. I do not want to make it selected. Please help.
After setting the menu please write below code in your on create method:
if(isloggedin){
// do click action which is required if the user already logged in
change your fragment from here
}else{
bottomnavigation.getMenu().getItem(your_position).setEnabled(false); // disable menu if user not logged in
Toast.makeText(CarerSeekerActivity.this,R.string.login_signup,Toast.LENGTH_SHORT).show();
}
I know I'm replying 3 years later, but this is the function I've done for changing all the tabs to clickable or not clickable. You can easily adapt it for what you asked.
private void setNavigationBarClickableItems(BottomNavigationBar bottomNavigationBar, boolean clickable) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) bottomNavigationBar.getChildAt(0);
for (int i = 0; i < menuView.getChildCount(); i++) {
menuView.getChildAt(i).setClickable(clickable);
}
}
I have a list, within a list, within a list, and so on. There's about 5 tiers.
It's easy enough to create 5 activities for each list on phones, but what if I want to support tablets as well? So I'd need to work with master detail flow.
However, I can't seem to find any tutorials or information in relations to a nested master detail flow.
Anyway, here is an illustration of what I'm describing:
In the tablet layout, I want the screen to shift 2 tiers at a time. User can advanced to the next tier by selecting a list item from the right tier. To go back to the previous tier, user can tap the back button.
Any idea how I can achieve this?
After a full day scouring the internet, I finally found a solution. To get a "Nested Master Details Flow" effect simply use a ViewPager with FragmentPageAdapter. The Master Detail Flow will look like this:
To change to a two panel mode when the user switches to landscape, in your extended FragmentPagerAdapter class, override the following method:
#Override
public float getPageWidth(int position) {
DisplayMetrics metrics = getResources().getDisplayMetrics();
// if the width is greater than 900dp halve the width of the page
if ((metrics.widthPixels / metrics.density) > 900) {
return (0.5f);
}
return super.getPageWidth(position);
}
To provide an "up button" for the view pager:
viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
// This method will be invoked when a new page becomes selected.
#Override
public void onPageSelected(int position) {
if (position == 0) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
});
You can tell the "up button" to go back a page like this (where viewpager is a member variable of your activity, holding the a reference to your ViewPager):
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int position = viewpager.getCurrentItem();
if (position > 0) viewpager.setCurrentItem(position-1);
return true;
}
REFERENCES:
ViewPager with FragmentPagerAdapter
Display back button on action bar
Multiple-View ViewPager Options
How to implement a ViewPager with different Fragments / Layouts and example github project
I am using a ToolBar Spinner to switch among the 6 activities of my App. The opening activity, which I call MainView, has only the spinner [plus a help link on the ToolBar action menu]. The user selects from the spinner which of the other 5 activities he wishes to run and when finished uses the ToolBar back button of that activity to return to MainView.
It all works fine except, after returning to MainView from any of the other activities, the name of that activity remains displayed in the Spinner, not MainView as i had expected. Plus, if user wants to return to that same activity he must select any of the others first.
I had thought that when the App returns to MainView using the ToolBar back button it would do so by calling the MainView OnCreate, and the MainView spinner would be recreated thus displaying MainView. But this appears to be not the case.
I have tried a few things including setSelection(0) in onCreate, re-initializing the spinner in onStart and onResume - but none has made a difference. Hope you can help.
xml for spinner ...
<Spinner
android:id="#+id/spinner_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
initialization code for spinner
String[] mainview_names = new String[]
{"MainView", "WebView", "JsoupView", "CodeView", "Connectivity", "FtpView"};
Spinner mainSpinner = (Spinner) findViewById(R.id.spinner_main);
ArrayAdapter<String> adapter = new ArrayAdapter<>
(this,android.R.layout.simple_spinner_dropdown_item, mainview_names);
mainSpinner.setAdapter(adapter);
mainSpinner.setOnItemSelectedListener(new CustomOnItemSelectedListener());
// mainSpinner.setSelection(0);
The Listener ...
public class CustomOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
switch (pos){
case 0: // Main View
break;
case 1: // Web View
BrowseWWW();
break;
case 2: // Jsoup View
LoadHTMLJsoup();
break;
case 3: // Code View
LoadHTMLCode();
break;
case 4: // Connectivity
GetHTMLConn();
break;
case 5: // Ftp View
GetHTMLFtp();
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
}
EDIT: Additional information:
The 5 activities each respond to the back button with code structured like this.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
help.setVisibility(View.GONE);
switch (item.getItemId()){
case android.R.id.home: // up navigation
finish();
return true;
case R.id.load:
// ....
}
return true;
case R.id.Clear
// ...
return true;
}
return false;
}
#Override
public void finish() {
Intent i = new Intent();
i.putExtra("urlKey", url.getText().toString());
i.putExtra("tokenKey", token.getText().toString());
i.putExtra("redirectsKey", HttpURLConnection.getFollowRedirects());
setResult(RESULT_OK, i);
super.finish();
}
Ok the spinner state issue:
Without digging into more of your code, here's my theory:
You're in activity A. You select something in the spinner, say B. Now you're in activity B and activity A is paused retaining state it had -- i.e. it has the item corresponding to B selected in the spinner. When you go back from B, activity A is resumed in that exact state and, of course, still has the B item in the spinner. You can't go to B again right away, because if you re-select B, your select handler will not be called (since there's no change).
The fact that Activity is not destroyed every time is probably what tricked you, that's why you should take a look at google guide on Activities -- it will probably save you a lot of guessing time :)
So, to fix your issue with spinners, you should override the onResume() method of each activity and use it to set the spinner to the state corresponding to that activity -- that's the short version.
Long version is, you're probably going somewhat against the flow using toolbar spinner to navigate between activities.
Navigation can be faster and more intuitive you implement your Web, Jsoup, Code and other top-level views as Fragments (also, this) inside a single Activity, that's exactly what they're for. It'll probably be more user-friendly to use Tabs instead of Spinner.
I have an app where I'm doing activity transitions for a company directory. When a search result is selected, the animation of their photo to the detail screen works. And if I hit the back button, the reverse animation occurs. However, if I hit the back arrow from the Toolbar, the reverse animation never occurs.
The detail screen is a new DetailActivity with a single fragment in it called DetailFragment. I'm not doing anything special on "onBackPressed". Should I be?
If you want the return transition to play, you'll need to listen for the up-navigation button click and call finishAfterTransition() directly:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finishAfterTransition();
return true;
}
return super.onOptionsItemSelected(item);
}
I have a Xamarin Android project that contains a menu bar. I'm almost certain this was working correctly yesterday, but since then, every time I click on a menu bar item such as 'settings', which takes me to the Settings Activity, then go back to the Main activity, the menu bar items are repeating themselves.
So where i just had 'Settings' and 'help', i not have 2 settings, and 2 help items. If i do it again, i will have 3 of each.
I'm assuming this is something to do with the onPause() and onResume() methods as the app goes to another activity. But i can't see where i'm going wrong (i'm new to Android)
My code for generating the menu bar in the Main Activity is:
public override bool OnPrepareOptionsMenu(IMenu menu1)
{
MenuInflater.Inflate(Resource.Menu.myMenuBar, menu1);
return base.OnPrepareOptionsMenu(menu1);
}
public override bool OnOptionsItemSelected(IMenuItem item) //do something when an options item is pressed
{
switch (item.ItemId)
{
case Resource.Id.settingsItem:
showSettings ();
return true;
case Resource.Id.helpItem:
//do something
return true;
}
return base.OnOptionsItemSelected(item);
}
Any ideas on this would be appreciated. I'm sure it's something fairly simple but I don't know what.
You should probably have to clear the menu
public override bool OnPrepareOptionsMenu(IMenu menu1)
{
menu1.clear();
MenuInflater.Inflate(Resource.Menu.myMenuBar, menu1);
return base.OnPrepareOptionsMenu(menu1);
}
And perhaps you should inflate the menu in the OnCreateOptionsMenu(IMenu, MenuInflater) method. OnPrepareOptionsMenu(IMenu) is meant for enabling/disabling and dynamically modifying items.