I have an Activity that has a tabhost and a ViewPager that support 3 fragments. I want to use the ActionBar (which resides in the Activity) to use and modify menu items selectable from the ActionBar directly in each of the fragments.
What is the best way to send a message from the activity to the fragment to tell it to implement one of the actionbar items?
I have tried the following:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
FragmentManager manager = getSupportFragmentManager();
List<Fragment> fs = new ArrayList<>(manager.getFragments());
int fragId = fs.get(0).getId();
PlayFragment fragment = (PlayFragment) manager.findFragmentById(fragId);
fragment.settingsMenu();
return true;
This is not working, but also is bad form to need to know the order of the fragments to get it to work. This way didn't work for me. I know I could use a broadcastSender to make it work, but that is also bad form. The REAL problem here is that since the fragments are sitting on top of a ViewPager within a TabHost, there is no way to get the id or tag reliably, so
manager.findFragmentById(fragId) and
manager.findFragmentByTag("MyFragmentName") are not useful.
When I try to attach the toolBar to an OnClickListener within the fragment, it doesn't work, and fragment has no support for
#Override public boolean onOptionsItemSelected(MenuItem item);
I'll keep looking for a solution. Thanks.
I found the answer on another post. The trick is to get the toolbar from the activity but not to use it as an actionbar directly. You need to inflate your own menu, and have access to modifying title etc ;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.play_fragment, container, false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = JamSessionApplication.getInstance();
toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
toolbar.setTitle(song);
// Set an OnMenuItemClickListener to handle menu item clicks
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_reverb) {
Toast.makeText(getActivity(), "Reverb", Toast.LENGTH_SHORT).show();
return true;
}
return true;
}
});
toolbar.inflateMenu(R.menu.menu_play);
}
I still encountered problems with ViewPager/Tabhost toobars working properly. I found an article which was much more helpful in fixing this.
https://www.numetriclabz.com/android-tabs-with-fragments-and-viewpager-tutorial/
Related
There seem to be many question related to this topic. When i read most of them i had one problem. Usually people try to make a fragment and then spawn a dialog fragment from there. So the dialog fragment is inside the fragment.
In my case i have created a button that opens a dialogfragment on the toolbar. Then i open my main fragment from the navigation bar. So the dialogfragment and my main fragment are getting called through the same main activity, just in different places. I cannot call the dialog fragment from inside the fragment since its getting called when the menu options are selected.
I tried to create a an interface with and a listener when im trying to
newFragment.setTargetFragment(somethinghere, 1); i have no idea on what i should be putting on the somethinghere field. getactivity,mealsworkoutfragment and .this are wrong)
I also tried to make my fragment extends Dialogfragment instead but this spawns my fragment everytime i press the button, which seems like an awful way to do this.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.date_picker) {
DialogFragment newFragment = new DatePickerFragment();
newFragment.show(getSupportFragmentManager(), "datePicker");
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.mealworkoutTab) {
iconShow = true;
invalidateOptionsMenu();
FragmentTransaction mealsworkoutsFrag = getSupportFragmentManager().beginTransaction();
mealsworkoutsFrag.replace(R.id.flMain,new MealsWorkoutsFragment());
mealsworkoutsFrag.commit();
} else if (id == R.id.userinfoTab) {
iconShow = false;
invalidateOptionsMenu();
FragmentTransaction userInfoFrag = getSupportFragmentManager().beginTransaction();
userInfoFrag.replace(R.id.flMain,new UserInfoFragment());
userInfoFrag.commit();
} else if (id == R.id.logoutTab) {
auth.signOut();
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Im guessing that a simple solution must exist since this looks a bit trivial (get sth from a dialogfragment to a fragment)
A suggestion would be to use library like EventBus in such cases to convey and listen listen to "events" and pass data. So in your case, when the user selects the date, an 'event' with the selected date payload is posted. This event is then caught inside your Fragment (because you make your Fragment subscribe to this specific event) and then you can handle the payload (selected date) as you like.
If the above sounds too tough to follow or picture, please visit the link above. It has example codes. This library is extremely simple to implement and quite helpful in such scenarios.
I have an app with a couple of activities. Until now I had a "hardcoded" hierarchy between them, so I had the android:parentActivityName set explicitly in each (but the launcher activity) of them. However now I added the Settings to the menu of more than one activity.
Is there a way to make the "back" arrow in the action bar function as the system's back button (in the bottom of the screen)? In other words: if there's a parentActivityName set, then it goes back to the parent activity, if not, then it closes the activity and "goes back" to the previous activity.
This is what I tried, but doesn't work. If I don't call actionBar.setDisplayHomeAsUpEnabled(true), then there's no "back" arrow in the action bar, but if I call it in an activity that doesn't have parentActivityName set in the Manifest, then I get an exception when I click the arrow.
abstract public class BaseActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());
final ActionBar actionBar = getSupportActionBar();
if (null != actionBar) {
actionBar.setDisplayHomeAsUpEnabled(getDisplayHomeAsUpEnabled());
}
}
protected abstract int getLayoutResourceId();
abstract protected boolean getDisplayHomeAsUpEnabled();
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
final int id = item.getItemId();
if (id == android.R.id.home) {
NavUtils.navigateUpFromSameTask(this);
return true;
}
}
}
Try :
if (id == android.R.id.home) {
onBackPressed();
return true;
}
The code above will call your onBackPressed, so be wary if you overrided it. Otherwise, it will be same like the "back" system button.
I'm programming an app based on the Weather App from Udacity Courses.
The app is based in a two activies: one general and other for weather detail with a fragment inside.
I've been experimenting with menu creation and I have and issue that I would like to comment with you all.
AFAIK, If I want to share an option between different fragments, it seems a good idea to put that option in the activity menu instead of the fragment menu, so that's what I'm doing with the Share button.
But I've seen that I have two possible situations:
1) If the menu item inside the xml is declared as showAsAction = never I can create the instance of the ShareActionProvider and the intent inside the onOptionsItemSelected, within the corresponding if sentence (and works fine):
public class DetailActivity extends Activity {
ShareActionProvider mShareActionProvider;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
getActionBar().setDisplayHomeAsUpEnabled(true);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction().add(R.id.container, new DetailFragment()).commit();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.detail, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
startActivity(new Intent(this, SettingsActivity.class));
return true;
}
if (id == R.id.action_share) {
mShareActionProvider = (ShareActionProvider) item.getActionProvider();
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "nada");
mShareActionProvider.setShareIntent(shareIntent);
return true;
}
return super.onOptionsItemSelected(item);
}
2) If the menu item is declared as showAsAction = always and the Share button is in the action bar, the above doesn't work as the Share button isn't even clickable. I have to declare the above code inside the onCreateOptionsMenu to make things work.
Why is that? Is different the chain of events for creating a menu when is not in the action bar Vs. when it's in it?
Thanks for the answers and excuse me for my english.
According to Google's document, getActionBar().setDisplayHomeAsUpEnabled(true) is needed to show the up button. I created a bare-bone activity using the wizard in Eclipse and specified its parent activity. I could not find any getActionBar().setDisplayHomeAsUpEnabled(true) in the automatically generated code, but the up button is present when this activity is started and it works as expected. Could anyone shed some light on this?
public class FooActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_foo);
//more code...
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//more code...
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//more code...
return rootView;
}
}
}
When you specify a parentActivityName in your AndroidManifest, Acitivty will check for that and automatically enable the "up" affordance if it's present.
I described all possible combinations below and their outcomes:
You have both android:parentActivityName=".MyActivityand this getActionBar().setDisplayHomeAsUpEnabled(true); - back button appears and it works;
You only have this android:parentActivityName=".MyActivity - back button appears and it works, the same as above;
You only have this getActionBar().setDisplayHomeAsUpEnabled(true);, - back button appears but clicking on it doesn't go anywhere;
You have set the parameter to false in this getActionBar().setDisplayHomeAsUpEnabled(false);, even though you have this android:parentActivityName=".MyActivity in the manifest, the back button doesn't show up.
That's how this works my friend.
I am developing an Android app, and last week I updates a few packages (dont remember which ones exactly) using SDK Manager. After restarting Eclipse, whenever I create a new Activity (with used to contain only onCreate and onCreateOptionsMenu methods), it creates an Activity with those two methods, plus the folowing code :
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_lmain,
container, false);
return rootView;
}
}
I am new with Android so Im not sure why is that hapening and how to "undo" those changes in order to be able to create a "normal" Activity as before.
Appreciate any help, thanks.
I think you are using Android Studio and and yes, Android Studio does create one fragment and an extra method when you create your application..
It's not an issue,.. you can just delete that fragment.xml and that extra code that's with some condition and the whole additional method for the fragment.
Then it will be fine.. I don't know why exactly it happens in Android Studio.