How to call NavController from fragment? - android

In my fragment_main.xml, I have the following code :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/bottomBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph='#navigation/bottom_bar_nav_graph' />
<!--custom bottom navigation ui-->
</androidx.constraintlayout.widget.ConstraintLayout>
I would like to have access to navController(***bottom_bar_nav_graph***) from fragment.
Is it possible?

If I get what you are trying to do correctly, you what to do something like
findViewbyId(R.id.bottom_bar_nav_graph)
which is not possible.
What this line of code is doing
app:navGraph='#navigation/bottom_bar_nav_graph'
is to let FragmentContainerView know about your graph bottom_bar_nav_graph which is an XML file that describes how your fragments relate, pass data and navigate between each other.
But can have access to nav_host_fragment which is the id for the host fragment.
If you want to access the navController with the id in Activity, you can use
val navController = findNavController(R.id.nav_host_fragment)

extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
private PageViewModel pageViewModel;
private FragmentMainBinding binding;
public static PlaceholderFragment newInstance(int index) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle bundle = new Bundle();
bundle.putInt(ARG_SECTION_NUMBER, index);
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pageViewModel = new ViewModelProvider(this).get(PageViewModel.class);
int index = 1;
if (getArguments() != null) {
index = getArguments().getInt(ARG_SECTION_NUMBER);
}
pageViewModel.setIndex(index);
}
#Override
public View onCreateView(
#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentMainBinding.inflate(inflater, container, false);
View root = binding.getRoot();
final TextView textView = binding.sectionLabel;
pageViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
textView.setText(s);
}
});
return root;
}

Related

get data from fragment to main activity null pointer exception

i have a problem that i cant find anywhere to solve, i am learning android studio from udemy, and the way the professor do fragment exercises dont work on me. He makes 2 fragments, one for list and one for details, the problem is when i am trying to componets to be read from mainactivity to run my tasks, there is a NullPointerException. Here is my Code:
DetailFragment
public class DetailFrag extends Fragment
{
ImageView imageView;
TextView tvName, tvTel;
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
public DetailFrag() {
// Required empty public constructor
}
public static DetailFrag newInstance(String param1, String param2) {
DetailFrag fragment = new DetailFrag();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_detail, container, false);
}
}
ListFragment
public class ListFrag extends Fragment {
RecyclerView recyclerView;
RecyclerView.Adapter myAdapter;
RecyclerView.LayoutManager layoutManager;
View view;
public ListFrag() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_list, container, false);
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView = view.findViewById(R.id.list);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this.getActivity());
recyclerView.setLayoutManager(layoutManager);
myAdapter = new PersonAdapter(this.getActivity(), ApplicationClass.people);
recyclerView.setAdapter(myAdapter);
}
}
MainActivity
public class MainActivity extends AppCompatActivity implements PersonAdapter.ItemClicked {
TextView tvName,tvTel;
EditText etName, etTel;
Button btnAdd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvName = findViewById(R.id.tvName)
tvTel = findViewById(R.id.tvTel);
etName = findViewById(R.id.etName);
etTel = findViewById(R.id.etTel);
btnAdd = findViewById(R.id.btnAdd);
btnAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
#Override
public void onItemClicked(int index) {
tvName.setText(ApplicationClass.people.get(index).getName());
tvTel.setText(ApplicationClass.people.get(index).getTelNr());
}
}
Exception:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.recyclerfragments, PID: 31089
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.example.recyclerfragments.MainActivity.onItemClicked(MainActivity.java:43)
at com.example.recyclerfragments.PersonAdapter$ViewHolder$1.onClick(PersonAdapter.java:46)
at android.view.View.performClick(View.java:7575)
at android.view.View.performClickInternal(View.java:7548)
at android.view.View.access$3600(View.java:837)
at android.view.View$PerformClick.run(View.java:28933)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:236)
Activity Main XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainerView"
android:name="com.example.recyclerfragments.ListFrag"
android:layout_width="200dp"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout="#layout/fragment_list" />
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/fragmentContainerView"
app:layout_constraintTop_toTopOf="parent">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainerView2"
android:name="com.example.recyclerfragments.DetailFrag"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
tools:layout="#layout/fragment_detail" />
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentContainerView3"
android:name="com.example.recyclerfragments.AddPersonFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"
tools:layout="#layout/fragment_add_person" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
According to the stacktrace given your issue is that tvTel or tvName is null i.e. the view you are trying to reference is not available on MainActivity. Reading your comments on the question it seems these views are present on Fragment and not on MainActivity.
Views of a fragment can be accessed on an Activity if and only if
fragment is attached to that Activity.
What it means in your code is that when you tried to use findViewById in onCreate of your MainActivity your fragment was not attached to your activity causing findViewById to return null.
Now to make your onItemClicked work you need shift findViewById to onItemClicked
#Override
public void onItemClicked(int index) {
if(tvName == null)
tvName = findViewById(R.id.tvName);
tvName.setText(ApplicationClass.people.get(index).getName());
if(tvTel == null)
tvTel = findViewById(R.id.tvTel);
tvTel.setText(ApplicationClass.people.get(index).getTelNr());
}
Above will fixed your issue of null view reference if fragment containing these view ids is attached to the activity.

Fragment in a tab layout is blank after pressing back button

I have a navhost where fragments are swapped in and out and inside the navhost is a tabLayout with 3 fragments in the 3 tabs. once I go from the contact fragment to the addContact fragment and press the back button, the contact fragment is blank, the other 2 fragments are also blank but after a short delay, the view will load for them but not the contact fragment. this video will show what I'm saying a bit better https://drive.google.com/file/d/1fQlzTWV04Su-Gdi98buTbq4PIYKhSj7u/view?usp=sharing.
I've seen other people have this problem but they are using fragment transaction whereas I'm using a nav graph for navigation
my Fragment with the tablayout (activity_message.xml)
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragments.MainMenuFragment">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="?actionBarSize"
android:padding="#dimen/appbar_padding"
android:text="#string/app_name"
android:textAppearance="#style/TextAppearance.Widget.AppCompat.Toolbar.Title" />
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" /></androidx.coordinatorlayout.widget.CoordinatorLayout>
my contact fragment (contact_fragment.xml)
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragments.contactFragment">
<!-- TODO: Update blank fragment layout -->
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#android:drawable/ic_dialog_email" /></androidx.constraintlayout.widget.ConstraintLayout>
my add contact fragment
public class AddContactFragment extends Fragment {
private Contact contact;
public AddContactFragment() {
}
public static AddContactFragment newInstance(){
AddContactFragment fragment = new AddContactFragment();
Bundle args = new Bundle();
//args.putString(ARG_PARAM1, param1);
//args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
#Override
public void handleOnBackPressed() {
Navigation.findNavController(getView()).navigate(R.id.action_addContactFragment_to_mainMenuFragment);
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.add_contact_fragment,container,false);
TextView nameHeading = view.findViewById(R.id.contactNameHeading);
TextView numberHeading = view.findViewById(R.id.contactNoHeading);
TextView idHeading = view.findViewById(R.id.contactIdHeading);
nameHeading.setText("Name");
numberHeading.setText("Phone Number");
numberHeading.setText("Account ID");
return view;
}
}
my contact fragment (one in the tab layout)
public class contactFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private ArrayList<Contact> contacts;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public contactFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment contactFragment.
*/
// TODO: Rename and change types and number of parameters
public static contactFragment newInstance(String param1, String param2) {
contactFragment fragment = new contactFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_contact, container, false);
RecyclerView rvContacts = (RecyclerView) view.findViewById(R.id.list);
contacts = Contact.createContactsList(50);
ContactsAdapter adapter = new ContactsAdapter(contacts);
rvContacts.setAdapter(adapter);
rvContacts.setLayoutManager(new LinearLayoutManager(getContext()));
FloatingActionButton fab = view.findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Navigation.findNavController(view).navigate(R.id.action_mainMenuFragment_to_addContactFragment);
}
});
return view;
}
}
my main menu fragment
public class MainMenuFragment extends Fragment {
public MainMenuFragment() {
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public static MainMenuFragment newInstance(String param1, String param2) {
MainMenuFragment fragment = new MainMenuFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_message,container,false);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this.getContext(), getFragmentManager());
ViewPager viewPager = view.findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = view.findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
return view;
}
}
my navhost (acvtivity_message_nav.xml)
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MessageActivity"
>
<fragment
android:id="#+id/fragment2"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph_message" /></androidx.constraintlayout.widget.ConstraintLayout>
my message activity
public class MessageActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message_nav);
}
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 1) {
finish();
} else {
super.onBackPressed();
}
}
}
my navgraph
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/nav_graph_message"
app:startDestination="#id/mainMenuFragment">
<fragment
android:id="#+id/addContactFragment"
android:name="com.example.encryptedsmsapp.Fragments.AddContactFragment"
android:label="AddContactFragment" >
<action
android:id="#+id/action_addContactFragment_to_mainMenuFragment"
app:destination="#id/mainMenuFragment" />
</fragment>
<fragment
android:id="#+id/contactFragment"
android:name="com.example.encryptedsmsapp.Fragments.contactFragment"
android:label="fragment_contact"
tools:layout="#layout/fragment_contact" >
<action
android:id="#+id/action_contactFragment_to_addContactFragment"
app:destination="#id/addContactFragment" />
</fragment>
<fragment
android:id="#+id/mainMenuFragment"
android:name="com.example.encryptedsmsapp.Fragments.MainMenuFragment"
android:label="activity_message"
tools:layout="#layout/activity_message" >
<action
android:id="#+id/action_mainMenuFragment_to_addContactFragment"
app:destination="#id/addContactFragment" />
</fragment>

How to used a shared transition from RecyclerView to a Fragment

I've seen this questioned asked a number of times on here without an answer. I'm hoping if I ask it again maybe someone will be kind enough to help me with it.
I'm trying to implement a shared transition from an Item in a Recyclerview to a fragment.
I currently have my fragment transaction in the onBindView method of the adapter.
public void onClick(View v) {
...
activity.getSupportFragmentMnager().beginTransaction()
.addSharedElement(v, "SharedString")
.replace(R.id.container, fragment2)
.addToBackStack(null)
.commit();
}
In the android docs, addSharedElement(view and string) confuse me. How do I give the view a unique ID and should I even be using v here?
Can the string be what ever I want?
here is my implementation. There is FragmentList with RecyclerView with images on each item. And there is FragmentDetail with only on big image. Image from FragmentList list item fly to FragmentDetail. TransitionName of animated view on FragmentList and FragmentDetail must be same. So I give unique transition name for each list item ImageView:
imageView.setTransitionName("anyString" + position)
Then I pass that string to FragmentDetail via setArguments and set big image transitionName to that string. Also we should provide Transition which describes how view from one view hierarchy animates to another viewhierarchy. After that we should pass that transition to fragment. I do it before FragmentTransaction:
detailFragment.setSharedElementEnterTransition(getTransition());
detailFragment.setSharedElementReturnTransition(getTransition());
Or you can override getSharedElementEnterTransition and getSharedElementReturnTransition of Fragment and declare transition there. Here is full code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new FragmentList())
.commit();
}
}
public void showDetail(View view) {
String transitionName = view.getTransitionName();
FragmentDetail fragment = new FragmentDetail();
fragment.setArguments(FragmentDetail.getBundle(transitionName));
fragment.setSharedElementEnterTransition(getTransition());
fragment.setSharedElementReturnTransition(getTransition());
getSupportFragmentManager()
.beginTransaction()
.addSharedElement(view, transitionName)
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
}
private Transition getTransition() {
TransitionSet set = new TransitionSet();
set.setOrdering(TransitionSet.ORDERING_TOGETHER);
set.addTransition(new ChangeBounds());
set.addTransition(new ChangeImageTransform());
set.addTransition(new ChangeTransform());
return set;
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" />
FragmentList:
public class FragmentList extends Fragment {
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.fragment_list, container, false);
RecyclerView rv = view.findViewById(R.id.recyclerview);
rv.setAdapter(new ListAdapter());
return view;
}
private class ListAdapter extends RecyclerView.Adapter {
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new Holder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Holder hold = (Holder) holder;
hold.itemView.setOnClickListener(v -> {
((MainActivity) getActivity()).showDetail(hold.imageView);
});
//unique string for each list item
hold.imageView.setTransitionName("anyString" + position);
}
#Override
public int getItemCount() {
return 10;
}
private class Holder extends ViewHolder {
ImageView imageView;
public Holder(View view) {
super(view);
imageView = view.findViewById(R.id.image);
}
}
}
}
fragment_list.xml
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
FragmentDetail:
public class FragmentDetail extends Fragment {
private static final String NAME_KEY = "key";
public static Bundle getBundle(String transitionName) {
Bundle args = new Bundle();
args.putString(NAME_KEY, transitionName);
return args;
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.fragment_detail, container, false);
String transitionName = getArguments().getString(NAME_KEY);
ImageView imageView = view.findViewById(R.id.image);
imageView.setTransitionName(transitionName);
return view;
}
}
fragment_detail.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="#+id/image"
android:layout_width="300dp"
android:layout_height="300dp"
android:src="#drawable/cat"/>
</LinearLayout>
item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="#+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/cat"/>
</LinearLayout>
Here is result:
TransitionName may be any string you want.
There is ViewCompat.setTransitionName if you need support pre Lollipop devices.
Adding to the ashakirov's answer:
Problem
Return Transition was not working!
Reason:
On popbackstack from Fragment B to Fragment A, Fragment A's onCreateView is called and if your data is still loading then the return transition won't work with only ashakirov's code.
Solution
Postpone the transition in your fragments
Add this line where the loading starts in your fragment A:
postponeEnterTransition();
After your data is loaded or you've set your adapter, write this:
startPostponedEnterTransition();
This ensures that your transition only happens after your data is loaded.
Also, make sure you start the transition even in 'data failed to load scenarios'.
If you want to postpone the transition in your fragment B when going from A to B then add this to your fragment B:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//hold the transition
postponeEnterTransition();
//when the views are available then start the transition
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
startPostponedEnterTransition();
return true;
}
});
}

Fragment is not showing up in activity

Trying to add Fragment to my Activity, but it isn't showing up.
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WeatherFragment mainFragment = new WeatherFragment();
getFragmentManager()
.beginTransaction()
.add(R.id.main_weather_container, mainFragment)
.commit();
}
}
And there is my fragment:
public class WeatherFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
boolean isAttachedToParent = false;
View inflatedView = inflater.inflate(R.layout.main_weather_fragment, container, isAttachedToParent);
return inflatedView;
}
}
R.id.main_weather_container - FrameLayout in my MainActivity.
R.layout.main_weather_fragment - Fragment's layout
What am i doing wrong?
I've tried to use FragmentActivity + v4 support fragment and fragmentSupportManager, but it didn't make any difference.
MainActivity xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/main_weather_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="#dimen/padding_16_dp" />
<android.support.v7.widget.RecyclerView
android:id="#+id/words_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3" />
</LinearLayout>
UPDATED: The problem wasn't in fragment transaction or whatever, i've used tools: namespace that's why fragment wasn't displayed. Sorry about that :(
try this way .in your activity call fragment
Fragment fragment = Video_fragment.newInstance();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.framecontainer, fragment).commit();
in fragment class.
public class Video_fragment extends Fragment{
View view;
public static Fragment newInstance() {
Video_fragment fragment = new Video_fragment();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view= inflater.inflate(R.layout.video_frag, container, false);
return view;
}
}
Create a instance of Fragment in WeatherFragment:
public static WeatherFragment newInstance() {
Bundle args = new Bundle();
WeatherFragment weatherFragment = new WeatherFragment();
weatherFragment.setArguments(args);
return weatherFragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_layout, container, false);
}
Inside your Activity in MainActivity :
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WeatherFragment weatherFragment = WeatherFragment.newInstance();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.flContainerId, weatherFragment)
.commit();
}
Your layout file will be:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/flContainerId"/>
public class WeatherFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View inflatedView = inflater.inflate(R.layout.main_weather_fragment, null, false);
return inflatedView;
}
}
As I can see, you are using AppCompatActivity but using getFragmentManager.
With AppCompatActivity you will need to use getSupportFragmentManager() rather than getFragmentManager()
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WeatherFragment mainFragment = new WeatherFragment();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.main_weather_container, mainFragment)
.commit();
}
}
Your WeatherFragment should be extend android.support.v4.app.Fragment;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="4"
android:orientation="vertical">
<FrameLayout
android:id="#+id/main_weather_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="#dimen/padding_16_dp" />
<android.support.v7.widget.RecyclerView
android:id="#+id/words_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3" />
</LinearLayout>
Added WeightSum in the parent Layout.

Pass data to Fragment from Layout before it's rendered

I need to pass data to a fragment, declared in activity layout before it is rendered:
<fragment android:name="com.app.fragments.MyFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/myFragment" />
I tried to do it in Activity's onCreate but fragment is already rendered at that time.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Here fragment is already rendered
mPosts = (MyFragment)getSupportFragmentManager().findFragmentById(R.id.myFragment);
mPosts.setData(someData);
}
I've seen the way when fragment is created programmatically in activity onCreate and than added to a container. It's not a very bad solution. But... Is there anything simpler?
For XML layout there is one question over here: https://stackoverflow.com/a/23226281/842607
Even they has to say you cannot pass arguments, but you can use callbacks or custom attributes.
Else
Normally, we use Bundle in arguments in this way:
Fragment class
public class ShopProductListingFragment extends Fragment {
private static final String TAG = ShopProductListingFragment.class.getSimpleName();
public static final String KEY_CATEGORY = "category";
public static final String KEY_URL_PARAMS = "url_params";
public static final String KEY_URL = "url";
public static ShopProductListingFragment getInstance(NewCategory category, #NonNull HashMap<String, String> urlParams) {
Bundle bundle = new Bundle();
if (null != category)
bundle.putLong(KEY_CATEGORY, category.getCategory_id());
bundle.putSerializable(KEY_URL_PARAMS, urlParams);
ShopProductListingFragment fragment = new ShopProductListingFragment();
fragment.setArguments(bundle);
return fragment;
}
public static ShopProductListingFragment getInstance(#NonNull String url) {
Bundle bundle = new Bundle();
bundle.putSerializable(KEY_URL, url);
ShopProductListingFragment fragment = new ShopProductListingFragment();
fragment.setArguments(bundle);
return fragment;
}
public ShopProductListingFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initVals();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_shop_product_listing, container, false);
ButterKnife.bind(this, rootView);
initViews();
return rootView;
}
private void initVals() {
Bundle bundle = getArguments();
if (null == bundle || Bundle.EMPTY == bundle)
throw new NullPointerException("Invalid or null arguments passed to fragment ShopProductListingFragment");
if (bundle.containsKey(KEY_CATEGORY))
categoryId = bundle.getLong(KEY_CATEGORY);
mCategory = StyFi.getInstance().getCategory(categoryId);
if (bundle.containsKey(KEY_URL_PARAMS))
urlParams = (HashMap<String, String>) bundle.getSerializable(KEY_URL_PARAMS);
if (bundle.containsKey(KEY_URL))
urlFilter = bundle.getString(KEY_URL);
}
}
Layout file of Activity
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
This is how it is instantiated in Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
if (null == savedInstanceState) {
ShopProductListingFragment fragment = ShopProductListingFragment.getInstance(category, getUrlParams(data));
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction().replace(R.id.content_frame, fragment, "SHOP");
fragmentTransaction.commit();
}
}

Categories

Resources