In my Android Studio project I have a TabView as a fragment of a Navigation Drawer Activity.
Fragment:
public class TabView extends Fragment {
View inflatedView;
TextView tvBalance;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
inflatedView = inflater.inflate(R.layout.delivery, container, false);
getActivity().setTitle("TabView");
TabLayout tabLayout = (TabLayout) inflatedView.findViewById(R.id.tabLayout);
tabLayout.addTab(tabLayout.newTab().setText("Tab_1"));
tabLayout.addTab(tabLayout.newTab().setText("Tab_2"));
tabLayout.addTab(tabLayout.newTab().setText("Tab_3"));
final ViewPager viewPager = (ViewPager) inflatedView.findViewById(R.id.viewpager);
viewPager.setAdapter(new PagerAdapter
(getFragmentManager(), tabLayout.getTabCount()));
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
return inflatedView;
}
public void updateBalance(String balance) {
if (inflatedView != null) {
tvBalance = inflatedView.findViewById(R.id.tvBalance);
tvBalance.setText("$" + balance);
}
Log.d("updateBalance", balance);
}
The UpdateBalance method is called in my MainActivity everytime the value changes. This works well as Log.d(...) prints the right value at the right time.
Somehow the Textfield does not change as if (inflatedView != null) is never true, although the fragment is displayed on screen.
Why is inflatedView allways null and how to avoid this problem?
I'm using TAGS when placing a fragment, and findFragmentByTag to test afterwards is a fragment is inflated... For example:
// Loading the fragment with a tag:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content, new HomeFragment(), "HOME_FRAGMENT");
ft.commit();
// then later check if the fragment is there:
HomeFragment fHome = (HomeFragment) getSupportFragmentManager().findFragmentByTag("HOME_FRAGMENT");
if (fHome != null && fHome.isVisible())
{
// my fragment is inflated and visible
}
Related
I have image in my fragment. I want click on the picture and... for example change the fragment. I have found the same topic How to setOnclick Listener to button in fragment but ClickListner does not work.
I have tried make the same code in Activity and onClickListner is work, but in the frame it does not work.
Below my code in the Fragment.
public class Fragment2 extends Fragment {
ImageView imageView;
MyListner listner;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View getview = inflater.inflate(R.layout.fragment_2, container, false);
imageView = (ImageView) getview.findViewById(R.id.imageView1);
imageView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
listner.callback();
}
});
return inflater.inflate(R.layout.fragment_2, container, false);
}
Below my interface
public interface MyListner {
public void callback();}
Below my MainActivity
public class MainActivity extends AppCompatActivity implements MyListner {
Fragment2 fragment2;
Fragment1 fragment1;
ImageView imageViewMain;
ImageView imageViewFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragment2 = new Fragment2();
setContentView(R.layout.activity_main);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();//начало транзакции объекта
ft.replace(R.id.container, fragment2);
ft.addToBackStack(null);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
#Override
public void callback() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();//начало транзакции объекта
ft.replace(R.id.container, fragment1);
ft.addToBackStack(null);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}}
Please, let me know where is the problem?
It seems you are inflating your fragment's view twice. Instead of this you need to return the view which you have already inflated as a result of your onCreateView inside Fragment2.
Try changing
return inflater.inflate(R.layout.fragment_2, container, false);
to
return getview;
I am using ViewPager2 along with TabLayout and TabLayoutMediator to display some fragments.
I have a problem when I leave the app (for example by tapping the home button) and then open it again, the TabLayout jumps to some other tabs. The correct tab, i.e. the last one the user was on when he left the app, is still selected and the correct fragment is still shown. It's just the tabs layout that gets scrolled to an unrelated position for some reason.
What can be the problem?
This is my code:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mViewModel = new ViewModelProvider(this).get(UserItemsViewModel.class);
viewPager = view.findViewById(R.id.view_pager);
tabLayout = view.findViewById(R.id.tab_layout);
viewPager.setAdapter(new ItemListFragmentAdapter(requireActivity(), mType));
tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager,
(tab, position) -> {
if (position == 0) {
tab.setText("All");
} else {
tab.setText(((ItemListFragmentAdapter) viewPager.getAdapter()).getItemAt(position - 1).getName());
}
}
);
mViewModel.getFormatsLD().observe(getViewLifecycleOwner(), new Observer<List<FormatItem>>() {
#Override
public void onChanged(List<FormatItem> formatItems) {
ItemListFragmentAdapter adapter = (ItemListFragmentAdapter) viewPager.getAdapter();
if (adapter != null) {
((ItemListFragmentAdapter) viewPager.getAdapter()).setItems(formatItems);
adapter.notifyDataSetChanged();
}
}
});
}
#Override
public void onResume() {
super.onResume();
tabLayoutMediator.attach();
viewPager.setCurrentItem(currentPage, false);
}
#Override
public void onPause() {
super.onPause();
currentPage = viewPager.getCurrentItem();
tabLayoutMediator.detach();
}
currentPage is a field in the parent fragment which hosts the ViewPager2 and TabLayout which is used to retain the last tab/page the user was on when the fragment got paused.
You can see in these photos below how it looks before leaving the app and after returning to it:
Remove .detach() and .attach() from on pause and move .attach() to onCreateView()
#Override
public void onResume() {
super.onResume();
viewPager.setCurrentItem(currentPage, false);
}
#Override
public void onPause() {
super.onPause();
currentPage = viewPager.getCurrentItem();
}
it's not necessary because garbage collection automatedly does so, but itconsidered as best practice
#Override
public void onDestroy() {
super.onDestroy();
tabLayoutMediator.detach();
}
There are lot of (duplicate) questions and answers are available, I went through almost all of them and failed. On reference of this question, I made some changes recently.
Brief : In my app, MainActivity holds Fragment View Pager and FrangmentA,B and C. FrangmentA Shows a DialogFragment CDialog onClik. After dismissing CDialog I need to Call FragmentA's doReload() which is not happening here.
MainActivity
protected void onCreate(Bundle savedInstanceState){
...
mSectionsPageAdapter = new FragmentAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
setupViewPager(mViewPager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
int defaultValue = 0;
int page = getIntent().getIntExtra("One", defaultValue);
mViewPager.setCurrentItem(page);
}
private void setupViewPager(ViewPager viewPager)
{
FragmentAdapter adapter = new
FragmentAdapter(getSupportFragmentManager());
adapter.addFragment(new FragmentA(), "FragA");
adapter.addFragment(new FragmentB(), "FragB");
adapter.addFragment(new FragmentC(), "FragC");
viewPager.setAdapter(adapter);
}
FragmentA
public class FragmentA extends Fragment implements CDialog.Dismissed{
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
...
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
FragmentManager fm = getActivity().getFragmentManager();
DialogFragment f = new CDialog();
f.show(fm, "CDialog");
}
});
#Override
public void dialogDismissed() {
Log.e(DFD_1, "dialogDismiss Called" );// <-- This is not working*
doReload();
}
}
And CDialogue
public class CDialog extends DialogFragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
....
return v;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
...
dfd_1.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
getDialog().dismiss(); //<--when this happens*
}
});
}
#Override
public void onDismiss(DialogInterface dialog) {
if (getActivity() != null && getActivity() instanceof Dismissed) {
((Dismissed) getActivity()).dialogDismissed();
}
super.onDismiss(dialog);
}
public interface Dismissed {
public void dialogDismissed(); //<-- FragmentA implements this
}
}
You can always have direct callback to your Fragment itself.
First step, is to set targetFragment using setTargetFragment():
DialogFragment#setTargetFragment(Fragment fragment, int requestCode);
I do it this way:
public void showDialogFragment(Fragment targetFragment, AppCompatDialogFragment appCompatDialogFragment, int requestCode) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
appCompatDialogFragment.setTargetFragment(targetFragment, requestCode);
fragmentTransaction.add(appCompatDialogFragment, appCompatDialogFragment.getClass().getSimpleName());
fragmentTransaction.commitAllowingStateLoss();
}
and then call to this method to open dialog fragment as:
public static final int RC_CDIALOG = 111;
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
showDialogFragment(FragmentA.this, new CDialog(), RC_CDIALOG);
}
});
Then, in your DialogFragment's onDismissListener(), have some code like below:
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (getTargetFragment() instanceof FragmentA)
((FragmentA) getTargetFragment()).doReload();
}
What you did this way is:
Show Dialog Fragment "CDialog" along with telling it that your target fragment is "FragmentA" whose reference you can use incase you have something to do with it. In your case you had to call doReload();
I have a TabLayout in a Fragment. I’m trying to switch tabs using DrawerLayout item. Not sure how to access the TabLayout from the parent Activity. Checked everywhere, to no avail.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize Toolbar and set it as the Action Bar
mToolbar = (Toolbar) findViewById(R.id.mToolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
// Inflate the TabFragment as the first one
mFragmentManager = getSupportFragmentManager();
mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.replace(R.id.containerView, new TabFragment()).commit();
// Initialize Drawer Menu
mDrawerLayout = (DrawerLayout) findViewById(R.id.mDrawerLayout);
mNavigationView = (NavigationView) findViewById(R.id.mNavigationView);
headerLayout = mNavigationView.getHeaderView(0);
// Set click events for the Drawer Menu items
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
// Close the Drawer Menu when an item is clicked
mDrawerLayout.closeDrawers();
switch (menuItem.getItemId()) {
case R.id.menuLessons:
return true;
case R.id.menuCheatSheet:
return true;
case R.id.menuMyProfile:
startActivity(new Intent(MainActivity.this, MyProfileActivity.class));
overridePendingTransition(R.anim.zoom_in, R.anim.fade_out);
return true;
default:
return true;
}
}
});
}
}
TabFragment.java
public class TabFragment extends Fragment {
public TabLayout mTabLayout;
public ViewPager mViewPager;
public static int int_items = 2;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the Tab Layout and setup View Pager
View x = inflater.inflate(R.layout.layout_tabs, null);
mTabLayout = (TabLayout) x.findViewById(R.id.mTabLayout);
mViewPager = (ViewPager) x.findViewById(R.id.mViewPager);
// Setup Adapter for the View Pager
mViewPager.setAdapter(new MyAdapter(getChildFragmentManager()));
return x;
}
private class MyAdapter extends FragmentPagerAdapter {
MyAdapter(FragmentManager fm) {
super(fm);
}
// Return Fragment with respect to position
#Override
public Fragment getItem(int position) {
switch(position) {
case 0 : return new LessonsFragment();
case 1 : return new CheatSheetFragment();
}
return null;
}
#Override
public int getCount() {
return int_items;
}
// Return title of the tab according to the position
#Override
public CharSequence getPageTitle(int position) {
switch(position) {
case 0 :
return "Lessons";
case 1 :
return "Cheat Sheet";
}
return null;
}
}
public void setCurrentTab(int tab_index) {
FragmentTabHost mTabHost = (FragmentTabHost)getActivity().findViewById(android.R.id.tabhost);
mTabHost.setCurrentTab(tab_index);
}
}
To get an instance to a Fragment in an activity, use:
Fragment tabFragment = (TabFragment) getSupportFragmentManager().findFragmentById(R.id.containerView);
Once you have this, you can then call your method:
tabFragment.setCurrentTab(/*tab index*/);
That answers the question, however I would consider using a ViewPager or simply sticking with tapping tabs to move to them instead of doing it view the nav drawer.
New to ActionBar and Fragments but familiar with Android in general.
I have been following a few tutorial. So far I have the following:
3 Fragments that I want to navigate between (each has an overriden onCreateView() and loads a simple view)
A custom TabListener for the ActionBar (I believe the problem is there, see bottom of post for code)
A hosting Activity in which this is all performed
The Activity code:
public class Activity_Home extends Activity
{
ActionBar actionBar;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
actionBar = getActionBar(); // Get reference to ActionBar
// Add some navigation tabs...
// 1. Enable ActionBar navigation tabs
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
// 2. Add the tabs
Tab programTab = actionBar.newTab();
Tab settingsTab = actionBar.newTab();
Tab historyTab = actionBar.newTab();
programTab.setText("Program")
.setTabListener(new TabListener<Fragment_Program>(
this, R.id.fragmentParent, Fragment_Program.class));
settingsTab.setText("Settings")
.setTabListener(new TabListener<Fragment_Settings>(
this, R.id.fragmentParent, Fragment_Settings.class));
historyTab.setText("History")
.setTabListener(new TabListener<Fragment_History>(
this, R.id.fragmentParent, Fragment_History.class));
actionBar.addTab(programTab);
actionBar.addTab(settingsTab);
actionBar.addTab(historyTab);
}
}
My Fragments:
public class Fragment_Program extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_program, null);
}
}
..
public class Fragment_History extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_history, null);
}
}
..
public class Fragment_Settings extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_settings, null);
}
}
Lastly, my TabListener which has been pretty much based on the official Google example. The fragmentContainer (int) is the XML resource ID of the LinearLayout in the Activities layout that is the direct parent of all of these Fragments.
public class TabListener <T extends Fragment> implements ActionBar.TabListener
{
private Fragment fragment;
private int fragmentContainer;
private final Activity activity;
private final Class<T> fragmentClass;
/** Constructor used each time a new tab is created.
* #param activity The host Activity, used to instantiate the fragment
* #param tag The identifier tag for the fragment
* #param fragmentClass The fragment's Class, used to instantiate the fragment
*/
public TabListener(Activity activity, int fragmentContainer, Class<T> fragmentClass)
{
this.activity = activity;
this.fragmentContainer = fragmentContainer;
this.fragmentClass = fragmentClass;
}
#Override
public void onTabReselected(Tab arg0, FragmentTransaction arg1)
{
// User selected the already selected tab. Usually do nothing.
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
// Check if the fragment is already intialized
if (fragment == null)
{
// If not, instatiate and add it to the Activity
fragment = Fragment.instantiate(activity, fragmentClass.getName());
ft.add(fragmentContainer, fragment);
}
else
{
ft.attach(fragment);
}
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
if (fragment != null)
{
// Detach the fragment, because another one is being attached
ft.detach(fragment);
}
}
}
So the app loads, the tabs are there, I can select them but they don't seem to be linked to each other and I am not really sure how to proceed.
Any suggestions would be great!
Cheers
BONUS QUESTION: The ActionBar is also below the existing ActionBar.. goal was to replace it, not make another one underneath.. again any suggestions would be great!
Fixed it!
I changed my approach from using the Fragment Container ID (which did make and does still make more sense to me..) with String tags as per this example Good complete Fragment and ActionBar example and the official Google example.
I imagine that you want the tabs to be connected in a way that you can swipe between tabs, in order to accomplish this, you should consider a ViewPager.
Here's the XML by the way:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
Here's some sample code you can use:
public class MyTabActivity extends FragmentActivity implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
//What item on the pager is being displayed
private int mCurPagerItem = 0;
//This will be set to the pageer to handle navigation
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
final ActionBar mActionBar = getActionBar();
mActionBar.setDisplayShowHomeEnabled(false);
mActionBar.setDisplayShowTitleEnabled(false);
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//add the tabs
mActionBar.addTab(mActionBar.newTab().setIcon(R.drawable.your_icon).setTabListener(this));
mActionBar.addTab(mActionBar.newTab().setIcon(R.drawable.your_icon2).setTabListener(this));
mActionBar.addTab(mActionBar.newTab().setIcon(R.drawable.your_icon3).setTabListener(this));
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(this);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
Fragment one = new Fragment_Program();
return one ;
case 1:
Fragment two = new Fragment_Settings();
return two ;
case 2:
Fragment three = new Fragment_History();
return three ;
default:
break;
}
return null;
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getString(R.string.title_one);
case 1:
return getString(R.string.title_two);
case 2:
return getString(R.string.title_three);
}
return null;
}
}
#Override
public void onPageScrollStateChanged(int arg0) {}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
#Override
public void onPageSelected(int arg0) {
//When a Page is selected, make that the current navigation item
getActionBar().setSelectedNavigationItem(arg0);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
//Back to top maybe?
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
//get the position
final int pos = tab.getPosition();
//Tell the viewpager to scroll to that page
mViewPager.setCurrentItem(pos);
mCurPagerItem = pos;
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
To answer your bonus question, on your Manifest, try adding the following line withing the specified activity tag:
android:uiOptions="splitActionBarWhenNarrow"