FindFragmentById returns null even with container id - android

I have an activity whose sole purpose is to show 5 different fragments in a frame layout. There are 5 buttons, each corresponding to one of the 5 fragments that can be displayed in the frame layout.
I'm trying to make it so that the activity doesn't respond to a button press of the button that corresponds to the SAME fragment, so that there are no animations or other unnecessary computation performed.
The problem is that BOTH findFragmentById and findFragmentByTag return null, even when I believe I'm passing in the correct parameter of the container view, i.e. the frame layout.
Here is how I dynamically switch the fragments when responding to button presses:
private void viewProfile(){
profile_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment profile = new ProfileFragment();
beginFragment(profile, "profile");
}
});
}
private void beginFragment(Fragment fragment, String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.animator.fade_in,
android.R.animator.fade_out);
fragmentTransaction.replace(R.id.fragment_display, fragment, tag);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
Here is how I'm trying to determine what fragment is being displayed in the container:
private void launchEvents(){
final Fragment current_frag = getSupportFragmentManager()
.findFragmentById(R.id.fragment_display);
events_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!current_frag.getTag().equals("events")) {
Fragment events = new EventsFragment();
beginFragment(events, "events");
events.setArguments(location_info);
}
}
});
}
And here is my XML file, in case I'm getting something wrong with the layout hierarchy:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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/home_screen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#323272"
tools:context=".HomeScreen">
<FrameLayout
android:id="#+id/fragment_display"
android:layout_width="match_parent"
android:layout_height="527dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
tools:background="#323272:color/background_dark">
</FrameLayout>
Any nudge in the right direction would be great! I feel so silly for being stuck on something so minor.

Move you findFragmentById in onClick methods as below and instant of checking a tag check the instanceof if fragment
private void launchEvents(){
events_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment current_frag = getSupportFragmentManager()
.findFragmentById(R.id.fragment_display);
if (!(current_frag instanceof EventsFragment)) {
Fragment events = new EventsFragment();
beginFragment(events, "events");
events.setArguments(location_info);
}
}
});
}

Related

How to fix fragment transaction not showing view unless app enters and returns from background?

Currently I am trying to add a new fragment on top of an existing fragment when a RecyclerView item is clicked. The behavior is not as expected. As shown in the below video. The fragment transaction works on the first try but once I leave the fragment and return (via the bottom bar) or scroll to the bottom of the list (which triggers pagination) the transaction no longer makes the desired fragment visible when item clicked.
However if I use the device menu button and bring the app back into the foreground, the correct fragment loads becomes visible.
Another odd behavior is that once the transaction seems to no longer work if I switch tabs using the bottom bar all fragments are replaced with blank screens. This is also fixed by the above method using the device menu button.
https://youtu.be/pYfdO5UB2Zc
activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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">
<FrameLayout
android:id="#+id/view_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/bottomBar" />
<com.roughike.bottombar.BottomBar
android:id="#+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
app:bb_tabXmlResource="#xml/bottombar_tabs"
app:bb_activeTabColor="#color/blue"
app:bb_titleTextAppearance="#style/BottomBarText"/>
</RelativeLayout>
activity.java
private FragmentTransaction mFragmentTransaction;
final Fragment mJobsFragment = JobsFragment.newInstance();
final Fragment mCalendarFragment = CalendarFragment.newInstance();
final Fragment mFeedFragment = FeedFragment.newInstance();
final Fragment mSettingsFragment = SettingsFragment.newInstance();
The addFragments() and setBottomBarTabSelectListener() are both called in the onCreate of the activity.
void addFragments () {
mFragmentTransaction =
getSupportFragmentManager().beginTransaction();
mFragmentTransaction.add(R.id.view_container, mSettingsFragment,
mSettingsFragment.getTag());
mFragmentTransaction.add(R.id.view_container, mFeedFragment,
mFeedFragment.getTag());
mFragmentTransaction.add(R.id.view_container, mCalendarFragment,
mCalendarFragment.getTag());
mFragmentTransaction.add(R.id.view_container, mJobsFragment,
mJobsFragment.getTag());
mFragmentTransaction.commit();
}
public void setBottomBarTabSelectListener(){
mBottomBar.setOnTabSelectListener(new OnTabSelectListener() {
#Override
public void onTabSelected(#IdRes int tabId) {
Fragment selectedFragment = null;
mFragmentTransaction = getSupportFragmentManager().beginTransaction();
if(tabId == R.id.tab_jobs){
selectedFragment = mJobsFragment;
}
else if(tabId == R.id.tab_calendar){
selectedFragment = mCalendarFragment;
}
else if(tabId == R.id.tab_feed){
selectedFragment = mFeedFragment;
}
else if(tabId == R.id.tab_settings){
selectedFragment = mSettingsFragment;
}
mFragmentTransaction.replace(R.id.view_container, selectedFragment);
mFragmentTransaction.commit();
}
});
}
This is called when a list item is clicked.
public void openJobDetails(){
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.view_container ,JobDetailFragment.newInstance());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
I have tested the item clicking and they are functioning properly. So there must be something with the Fragments and the Transaction that I am missing.
try this code:
private jobDetailFragment = JobDetailFragment.newInstance();
public void openJobDetails(){
FragmentTransaction fragmentTransaction =
getChildFragmentManager().beginTransaction();
fragmentTransaction.executePendingTransactions();
if(jobDetailFragment.isAdded()){
fragmentTransaction.show(jobDetailFragment);
} else {
fragmentTransaction.add(R.id.view_container, jobDetailFragment);
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
I think it's better add fragment once and use hide/show to switch fragment, use isAdded() to check add status, I mean for the four bottom tabs .And maybe start a new activity for jobDetail is a better way~
And you should do something to avoid Activity State Loss. See this: https://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
I have encountered a similar problem and fixed it by re-adding fragments in onResume()
protected void onResume() {
super.onResume();
Log.d(tag,"onResume");
addFragments ();
}

fragments overlaps after activity is recreated

In my sample, I try to learn the difference between commitAllowingStateLoss() and commit() methods for fragments. Now I know IllegalArgumentException will appear if using commit() after activity save instance (for example, executed commit() when activity was in background).
But another problem appears, fragments overlap. I don't know why, and cannot solve the problem.
My code is as below.
In FragmentMainActivity there are two buttons for switching fragments.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/btn_fragment1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="fragment 1" />
<Button
android:id="#+id/btn_fragment2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="fragment 2" />
</LinearLayout>
<FrameLayout
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffffff"></FrameLayout>
The framelayout with id "root" is the container for fragments.
public class FragmentMainActivity extends AppCompatActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_main);
findViewById(R.id.btn_fragment1).setOnClickListener(this);
findViewById(R.id.btn_fragment2).setOnClickListener(this);
}
PlusOneFragment plusOneFragment;
PlusTwoFragment plusTwoFragment;
#Override
public void onClick(View v) {
int i = v.getId();
if (i == R.id.btn_fragment1) {
findViewById(R.id.root).postDelayed(new Runnable() {
#Override
public void run() {
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (getSupportFragmentManager().findFragmentByTag("tag1") == null) {
plusOneFragment = PlusOneFragment.newInstance("1", "2");
transaction.add(R.id.root, plusOneFragment, "tag1");
} else {
plusOneFragment = (PlusOneFragment) getSupportFragmentManager().findFragmentByTag("tag1");
}
if (getSupportFragmentManager().findFragmentByTag("tag2") != null) {
plusTwoFragment = (PlusTwoFragment) getSupportFragmentManager().findFragmentByTag("tag2");
transaction.hide(plusTwoFragment);
}
transaction.show(plusOneFragment).commitAllowingStateLoss();
}
}, 3000);
} else if (i == R.id.btn_fragment2) {
findViewById(R.id.root).postDelayed(new Runnable() {
#Override
public void run() {
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (getSupportFragmentManager().findFragmentByTag("tag2") == null) {
plusTwoFragment = PlusTwoFragment.newInstance("1", "2");
transaction.add(R.id.root, plusTwoFragment, "tag2");
} else {
plusTwoFragment = (PlusTwoFragment) getSupportFragmentManager().findFragmentByTag("tag2");
}
if (getSupportFragmentManager().findFragmentByTag("tag1") != null) {
plusOneFragment = (PlusOneFragment) getSupportFragmentManager().findFragmentByTag("tag1");
transaction.hide(plusOneFragment);
}
transaction.show(plusTwoFragment).commitAllowingStateLoss();
}
}, 3000);
}
}
}
First I click button1 to show fragment1, then click button2 to show fragment2, it works fine. After those operations, I click button1 again, and then click home, so the app is running in background. To simulated low memorey scene, I then kill the process. All those operations happened in 3s.
Finally, I opened the app from the recent records (activity recreated), found that the two fragments overlapped with each other. How does this happen?(why the problem not happened when the process is foreground?) And what can I do with this problem?
Give your fragments root element a background color (say white) android:background="#android:color/white"
and check again.
This is beacuse your fragments are not removed and added one over another.Also try replace methods instead of add.For ex:-
fragmentTransaction.replace("containerId", fragment);
as this replaces the previous fragment in layout.You can manually remove your fragment as well using
Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if(fragment != null)
getSupportFragmentManager().beginTransaction().remove(fragment).commit();
As fragment remains in backstack you have to remove first fragment from backstack when second is opening. Using popBackStack may resolve your problem
Fragment fragment = (Fragment) YourClass.newInstance();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.flContent, fragment);
//TODO Add to backstack
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
I hope this may help you

Dynamically change content of a drawer using fragments

I need to change the drawer content dynamically. I plan to do it with fragments. Means start new fragments to change the view of drawer. Actually my drawer itself a fragment. I have given code like this inside the first fragment:
#Override
public void onActivityCreated (Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
LinearLayout helpLL = (LinearLayout) getView().findViewById(R.id.helpLL);
helpLL.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Fragment detail = new DetailFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.left_drawer, detail).commit();
}
});
}
I need to change the entire drawer view with this layout. left_drawer is the view in main.xml where my first fragment lies. But when I click, nothing is happening.
Please tell me what wrong I did with this code.
Thanks
Jomia
I finally found the solution. I did a mistake in my code.Actually I hard coded the fragment in xml for the first drawer. Fragments that are hard coded in XML, cannot be replaced. Thats why the second fragment is not created.
So I added the first fragment dynamically. Now it is working fine..
In main.xml
<LinearLayout android:layout_width="240dp"
android:layout_height="match_parent"
android:id="#+id/left_drawer"
android:layout_weight="1"
android:layout_gravity="right"
android:orientation="vertical">
</LinearLayout>
In Activity
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
settingsFragment = new SettingsFragment();
fragmentTransaction.add(R.id.left_drawer, settingsFragment, "settingsFragment");
fragmentTransaction.commit();
In SettingsFragment.java
#Override
public void onActivityCreated (Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
LinearLayout helpLL = (LinearLayout) getView().findViewById(R.id.helpLL);
helpLL.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Fragment detail = new DetailFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.left_drawer, detail,"Details").commit();
}
});
}
Thats all...

How to start shared element transition using Fragments?

I am trying to implement transitions between fragments which have "shared elements" as described in the new material design specs.
The only method I can find is the ActivityOptionsCompat.makeSceneTransitionAnimation, which I believe works on Activity only.
I've been searching for this same functionality but with/for fragments.
I had the same problem but had it working by adding a new fragment from another fragment.
The following link is very helpful in getting started on this: https://developer.android.com/training/material/animations.html#Transitions
Following is my code that works. I'm animating an ImageView from one fragment to the other.
Make sure the View you want to animate has the same android:transitionName in both fragments.
The other content doesn't really matter.
As a test, you could copy this to both your layout xml files. Make sure the image exists.
<ImageView
android:transitionName="MyTransition"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/test_image" />
Then I have 1 file in my res/transition folder, named change_image_transform.xml.
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform />
</transitionSet>
Now you can get started. Lets say you have Fragment A containing the image and want to add Fragment B.
Run this in Fragment A:
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.product_detail_image_click_area:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));
// Create new fragment to add (Fragment B)
Fragment fragment = new ImageFragment();
fragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
fragment.setEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));
// Our shared element (in Fragment A)
mProductImage = (ImageView) mLayout.findViewById(R.id.product_detail_image);
// Add Fragment B
FragmentTransaction ft = getFragmentManager().beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack("transaction")
.addSharedElement(mProductImage, "MyTransition");
ft.commit();
}
else {
// Code to run on older devices
}
break;
}
}
The shared element fragment transitions do work with ListViews, as long as the source and target views have the same (and unique) transitionName.
If you make your list view adapter to set unique transitionNames to the views you want (e.g. some constant + specific item id) and also change your detail fragment to set the same transitionNames to the target views at runtime (onCreateView), the transitions actually work!
Shared elements do work with Fragments but there are some things to keep in mind:
Don't try to set the sharedElementsTransition in the onCreateView of your Fragment. You have to define them when creating an instance of your Fragment or in onCreate.
Take note of the official documentation on the possible animations for enter/exit transitions & sharedElementTransition. They are not the same.
Trial and error :)
This should be a comment to the accepted answer, as I am unable to comment on it.
The accepted answer (by WindsurferOak and ar34z) works, except for a "minor" problem which caused a null pointer exception when navigating up with the backStack. It seems that setSharedElementReturnTransition() should be called on the target fragment instead of the original fragment.
So instead of:
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
it should be
fragment.setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
https://github.com/tevjef/Rutgers-Course-Tracker/issues/8
Following are some helpful resources:
https://github.com/lgvalle/Material-Animations
http://www.androiddesignpatterns.com/2014/12/activity-fragment-transitions-in-android-lollipop-part1.html
https://www.youtube.com/watch?v=5e1Yh0fSZhQ
The key is to use a custom transaction with
transaction.addSharedElement(sharedElement, "sharedImage");
Shared Element Transition Between Two Fragments
In this example, one of two different ImageViews should be translated from the ChooserFragment to the DetailFragment.
In the ChooserFragment layout we need the unique transitionName attributes:
<ImageView
android:id="#+id/image_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_first"
android:transitionName="fistImage" />
<ImageView
android:id="#+id/image_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_second"
android:transitionName="secondImage" />
In the ChooserFragments class, we need to pass the View which was clicked and an ID to the parent Activity wich is handling the replacement of the fragments (we need the ID to know which image resource to show in the DetailFragment). How to pass information to a parent activity in detail is surely covered in another documentation.
view.findViewById(R.id.image_first).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mCallback != null) {
mCallback.showDetailFragment(view, 1);
}
}
});
view.findViewById(R.id.image_second).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mCallback != null) {
mCallback.showDetailFragment(view, 2);
}
}
});
In the DetailFragment, the ImageView of the shared element also needs the unique transitionName attribute.
<ImageView
android:id="#+id/image_shared"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:transitionName="sharedImage" />
In the onCreateView() method of the DetailFragment, we have to decide which image resource should be shown (if we don't do that, the shared element will disappear after the transition).
public static DetailFragment newInstance(Bundle args) {
DetailFragment fragment = new DetailFragment();
fragment.setArguments(args);
return fragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_detail, container, false);
ImageView sharedImage = (ImageView) view.findViewById(R.id.image_shared);
// Check which resource should be shown.
int type = getArguments().getInt("type");
// Show image based on the type.
switch (type) {
case 1:
sharedImage.setBackgroundResource(R.drawable.ic_first);
break;
case 2:
sharedImage.setBackgroundResource(R.drawable.ic_second);
break;
}
return view;
}
The parent Activity is receiving the callbacks and handles the replacement of the fragments.
#Override
public void showDetailFragment(View sharedElement, int type) {
// Get the chooser fragment, which is shown in the moment.
Fragment chooserFragment = getFragmentManager().findFragmentById(R.id.fragment_container);
// Set up the DetailFragment and put the type as argument.
Bundle args = new Bundle();
args.putInt("type", type);
Fragment fragment = DetailFragment.newInstance(args);
// Set up the transaction.
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Define the shared element transition.
fragment.setSharedElementEnterTransition(new DetailsTransition());
fragment.setSharedElementReturnTransition(new DetailsTransition());
// The rest of the views are just fading in/out.
fragment.setEnterTransition(new Fade());
chooserFragment.setExitTransition(new Fade());
// Now use the image's view and the target transitionName to define the shared element.
transaction.addSharedElement(sharedElement, "sharedImage");
// Replace the fragment.
transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName());
// Enable back navigation with shared element transitions.
transaction.addToBackStack(fragment.getClass().getSimpleName());
// Finally press play.
transaction.commit();
}
Not to forget - the Transition itself. This example moves and scales the shared element.
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class DetailsTransition extends TransitionSet {
public DetailsTransition() {
setOrdering(ORDERING_TOGETHER);
addTransition(new ChangeBounds()).
addTransition(new ChangeTransform()).
addTransition(new ChangeImageTransform());
}
}
I searched for SharedElement in fragments and I find very useful source code on GitHub.
1.first you should define transitionName for your Objects(Like ImageView) in both Fragments layout(We add a button in fragment A for handling click event):
fragment A:
<ImageView
android:id="#+id/fragment_a_imageView"
android:layout_width="128dp"
android:layout_height="96dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="80dp"
android:scaleType="centerCrop"
android:src="#drawable/gorilla"
android:transitionName="#string/simple_fragment_transition />
<Button
android:id="#+id/fragment_a_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="24dp"
android:text="#string/gorilla" />
fragment B:
<ImageView
android:id="#+id/fragment_b_image"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:src="#drawable/gorilla"
android:transitionName="#string/simple_fragment_transition" />
Then you should write this code in your transition file in transition Directory(if you haven't this Directory so create One: res > new > Android Resource Directory > Resource Type = transition > name = change_image_transform ):
change_image_transform.xml:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<changeImageTransform/>
</transitionSet>
In the last step you should complete codes in java:
fragment A:
public class FragmentA extends Fragment {
public static final String TAG = FragmentA.class.getSimpleName();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final ImageView imageView = (ImageView) view.findViewById(R.id.fragment_a_imageView);
Button button = (Button) view.findViewById(R.id.fragment_a_btn);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getFragmentManager()
.beginTransaction()
.addSharedElement(imageView, ViewCompat.getTransitionName(imageView))
.addToBackStack(TAG)
.replace(R.id.content, new FragmentB())
.commit();
}
});
}
}
fragment B:
public class FragmentB extends Fragment {
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_b, container, false);
}
}
don't forget to show your "A" fragment in your activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.content, new SimpleFragmentA())
.commit();
}
source : https://github.com/mikescamell/shared-element-transitions
How to start shared element transition using Fragments?
I assume you want to transition of your Image using Fragment (instead of Activity)
it wont work perfectly if you have already set AppTheme
keep the transition name of source and destination same
You have to do three things for transition:
1.Set transitionName to the source View(xml or programatically) -> before calling makeFragmentTransition
private void setImageZoom(boolean isImageZoom) {
ImageView imageView = this.findViewById(R.id.image);
if (isImageZoom) {
imageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ViewCompat.setTransitionName(imageView, "imageTransition");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
makeFragmentTransition(imageView);
}
}
});
}
}
2.Fragment Transition
Set TransitionSet for the specicific Transition animation
apply them on Fragment
call addSharedElement(View, transitionName) while fragmentTransition
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public void makeFragmentTransition(ImageView sourceTransitionView) {
//transtionName for sourceView
//MUST set transitionName before calling this method(programattically or give ->transitionName to the view in xml)
String sourceTransitionName = ViewCompat.getTransitionName(sourceTransitionView);
TransitionSet transitionSet = new TransitionSet();
transitionSet.setDuration(500);
transitionSet.addTransition(new ChangeBounds()); //to expand boundaries
transitionSet.addTransition(new ChangeTransform()); //for transtion vertically
transitionSet.addTransition(new ChangeImageTransform()); // image transform work
transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER);
ImageTransitionFragment fragment = new ImageTransitionFragment();
fragment.setSharedElementEnterTransition(transitionSet);
fragment.setSharedElementReturnTransition(transitionSet);
fragment.setAllowReturnTransitionOverlap(false);
try {
getHostActivity().getSupportFragmentManager()
.beginTransaction()
//sharedElement is set here for fragment
//it will throw exception if transitionName is not same for source and destionationView
.addSharedElement(sourceTransitionView, sourceTransitionName)
//R.id.fragmentView is the View in activity on which fragment will load...
.replace(R.id.fragmentView, fragment)
.addToBackStack(null)
.commit();
} catch (Exception e) {
//
String string = e.toString();
}
}
3.set desitionNation transitionName in ImageView
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/destionationTransitionPage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:transitionName="#string/pageTransition"
android:background="#color/black_color">
<com.android.foundation.ui.component.FNImageView
android:id="#+id/destinationImageView"
android:layout_width="#dimen/_400dp"
android:layout_gravity="center"
android:transitionName="imageTransition"
android:layout_height="#dimen/_400dp" />
</FrameLayout>
Please respond if anything is not clear or it need more improvement

replace the Fragment within the tab(Without viewpager)

I have 2 tabs in my app.Each have single fragment initially.
Scenario 1(Tab 1):
I 'm adding a second fragment in the tab on Button Click from the first fragment & again a third fragment on button click from second fragment.
Scenario 2(Tab 2):
Similar as tab1
Scenario 2(Switch between the Tab):
As I switch between the tab.I'm unable to get same tab fragment which I have added in the respective tab.
Below is my code:(First Fragment Tab1)
public class ArticleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup view=(ViewGroup) inflater.inflate(R.layout.article_fragment, container,false);
fragmentTabHost.setup(getActivity(), getChildFragmentManager() , R.id.frag_container);
Button article_button = (Button) view.findViewById(R.id.article_btn);
article_button.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
article_txt.setText("Changed Value");
ArticleDetails articleFragment = new ArticleDetails();
fragmentTransaction.add(ScreenFragmentActivity.getContainertId(), articleFragment, AppConstants.ARTICLE_FRAGMENT_DETAILS);
fragmentTransaction.hide(ArticleFragment.this);
fragmentTransaction.addToBackStack(ArticleFragment.class.getName());
fragmentTransaction.commit();
}
});
return view;
}
}
Second Fragment Tab1:
public class ArticleDetails extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
ViewGroup view=(ViewGroup) inflater.inflate(R.layout.article_details, container,false);
Button article_button = (Button) view.findViewById(R.id.article_details_btn);
article_button.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
ArticleDetailsWithIn articleFragment = new ArticleDetailsWithIn();
fragmentTransaction.add(ScreenFragmentActivity.getContainertId(), articleFragment,
AppConstants.ARTICLE_FRAGMENT_DETAILS_WITHIN);
fragmentTransaction.hide(ArticleDetails.this);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
return view;
}
My Layout:
<android.support.v4.app.FragmentTabHost
android:id="#+id/tabhost"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TabWidget
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="horizontal" />
<FrameLayout
android:id="#+id/tabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
So Basically I'm trying to add the new Fragment within the tab .But on Switch I'm not able to retain my respective fragment
You can try this - tag your fragments with some name and store this in any static helper class using getter/setter method. Make your first fragment tag name as default (this is for first time launch). Then at place where you have logic to add new fragments, put the required if-else statements. Same goes for other tab also. (you can even use shared preferences, if you want to remember last seen fragment even when app is closed and restarted again.)
Create a static helper class.
public class HelperClass {
private static string TabOneFragmentOnScreen = "";
public static String getTabOneFragmentOnScreen () {
return TabOneFragmentOnScreen ;
}
public static void setTabOneFragmentOnScreen(
String TabOneFragmentOnScreen) {
HelperClass.TabOneFragmentOnScreen = TabOneFragmentOnScreen;
}
}
When you click one TabOne
if(HelperClass.getTabOneFragmentOnScreen.equals("")){
HelperClass.setTabOneFragmentOnScreen("FragmentOne");
//logic to add fragment one goes here
}
if(HelperClass.getTabOneFragmentOnScreen.equals("FragmentTwo")){
HelperClass.setTabOneFragmentOnScreen("FragmentTwo");
//logic to add fragment two goes here
}
This way it will always remember the last fragment on screen under tab one.
This code is not complete, but you can develop further on this logic.

Categories

Resources