Android activity and fragment transition animation - android

I have two activities, both of them will initial a fragment within its activity layout. However, I have trouble adding animation from activity A to activity B. The transition works just fine. Here is some code snippet.
I've tried using overridePending, which basically does nothing. Also, I tried adding custom animation through .setCustomAnimations() in fragmentManager. However, I could only see the second animation slide in but not sliding out. And no animation at all for the first activity.
Main Activity (Activity A):
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null){
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, new MainFragment())
.commit();
}
}
public void gotToCommentActivityWithPostId(String postId){
Intent intent = new Intent(this, CommentActivity.class);
Bundle b = new Bundle();
b.putString(CommentActivity.POST_ID_KEY, postId);
intent.putExtras(b);
startActivity(intent);
}
}
Main Activity layout:
<android.support.constraint.ConstraintLayout 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"
tools:context="yaojungyang.testing.Screens.MainScreen.MainActivity">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</android.support.constraint.ConstraintLayout>
Destination Activity(Activity B):
public class CommentActivity extends AppCompatActivity {
public static final String POST_ID_KEY = "POST_ID_KEY";
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.comment_activity_layout);
if(savedInstanceState == null){
Bundle bundle = new Bundle();
bundle.putString(POST_ID_KEY, getIntent().getStringExtra(POST_ID_KEY));
Fragment fragment = new CommentFragment();
fragment.setArguments(bundle);
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.slide_from_right, R.anim.slide_to_right, R.anim.slide_to_right, R.anim.slide_to_right)
.add(R.id.fragment_container, fragment)
.commit();
}
}
}
Destination Activity layout:
<android.support.constraint.ConstraintLayout 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"
tools:context="yaojungyang.testing.Screens.MainScreen.MainActivity">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>

Related

findFragmentById returns null always

I have one MainActivity and two fragments FGames and FGameDetail. I am trying to communicate between them so that when an item is clicked in the FGames it passes GameEntity to MainActivity and it updates the FGameDetail. I have separate layout created for phone and tablet.
In my MainActivity where I am controlling if the FGameDetail fragment exists in the layout update the view. but findFragmentById always returns null for both FGames and FGameDetails.
Here is my layout for Phones and Tablets
layout\activity_main.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:id="#+id/games_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.rao.igttest.MainActivity">
<fragment
android:id="#+id/fragment_fGames"
android:name="com.example.rao.igttest.Games.View.FGames"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
layout-large-land\activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/fragment_fGames"
android:name="com.example.rao.igttest.Games.View.FGames"
android:layout_width="400dp"
android:layout_height="wrap_content" />
<fragment
android:id="#+id/fragment_fGameDetail"
android:name="com.example.rao.igttest.Games.View.FGameDetail"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
MainActivity
public class MainActivity extends AppCompatActivity implements FGames.OnGameSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//FGames fGames = new FGames();
//getSupportFragmentManager().beginTransaction().add(R.id.games_container, fGames).commit();
}
#Override
public void onGameSelected(GameEntity gameEntity) {
FragmentManager fragmentManager = getSupportFragmentManager();
FGameDetail gameDetailFrag = (FGameDetail) fragmentManager
.findFragmentById(R.id.fragment_fGameDetail);
Fragment gameFrag = fragmentManager.findFragmentById(R.id.fragment_fGames);
if (gameDetailFrag == null) {
//TODO Open a new intent
} else {
// DisplayFragment (Fragment B) is in the layout (tablet layout),
// so tell the fragment to update
FGameDetail fGameDetail = new FGameDetail();
fGameDetail.updateContent(gameEntity);
}
}
}
Your help and suggestions is much appreciated.
EDIT
FGAMES
#Override
public void initRecyclerView(List<GameEntity> gameEntities) {
gamesAdapter = new GamesAdapter(getActivity(), gameEntities);
rvGames.setAdapter(gamesAdapter);
rvGames.setLayoutManager(new LinearLayoutManager(getActivity()));
}
GamesAdapter
//Constructor
public GamesAdapter(Context context, List<GameEntity> gameEntities) {
layoutInflater = LayoutInflater.from(context);
this.data = gameEntities;
this.context = context;
}
#OnClick(R.id.row_container)
void rowClick(){
//I think as I am creating a new instance here as I dont have referencec to GamesPresenter in adapter as I am calling it directly from FGames
GamesPresenter gamesPresenter = new GamesPresenterImpl();
gamesPresenter.showGameDetail(data.get(getLayoutPosition()));
Toast.makeText(context, "itemClicked " + data.get(getLayoutPosition()), Toast.LENGTH_SHORT).show();
}
GamesPresenterImpl
#Override
public void showGameDetail(GameEntity gameEntity) {
GamesView gamesView = new FGames();
gamesView.onListItemClick(gameEntity);
}
FGames
#Override
public void onListItemClick(GameEntity gameEntity) {
OnGameSelectedListener mListener = new MainActivity();
mListener.onGameSelected(gameEntity);
}
public interface OnGameSelectedListener{
public void onGameSelected(GameEntity gameEntity);
}
MainActivity - OnGameSelected.
#Override
public void onGameSelected(GameEntity gameEntity) {
FragmentManager fragmentManager = getSupportFragmentManager();
FGameDetail gameDetailFrag = (FGameDetail) fragmentManager
.findFragmentById(R.id.fragment_fGameDetail);
Fragment gameFrag = fragmentManager.findFragmentById(R.id.fragment_fGames);
if (gameDetailFrag == null) {
} else {
// DisplayFragment (Fragment B) is in the layout (tablet layout),
// so tell the fragment to update
FGameDetail fGameDetail = new FGameDetail();
fGameDetail.updateContent(gameEntity);
}
}
Are you sure you are not doing new MainActivity().onGameSelected(object)?
If you using the Interactor fragment pattern, you must use the instance of the Activity you already have in the class.
Also, this line dont update the screen cause you creating a new instance of the fragment that will never be added:
FGameDetail fGameDetail = new FGameDetail();
fGameDetail.updateContent(gameEntity);
There is a instance already in screen so:
gameDetailFrag.updateContent(gameEntity);

How to toggle between fragments

I have an app that has 1 Main Activity and 5 main fragments. When the MainActivity is created I create a List containing each of the 5 fragments. The user is presented with a tab bar on the bottom of the screen which he/she can use to navigate between fragments. How do I set this up so as when the user selects a tab, the corresponding fragment is shown without creating a new instance of it? Just want to change the view on the screen to the already created fragment.
I am using a BottomBar from https://github.com/roughike/BottomBar which calls a "onTabSelected" interface method when a tab is pressed.
You can use 5 Fragments with the library you specified like this. The layout file should look like this
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- This could be your fragment container, or something -->
<FrameLayout
android:id="#+id/contentContainer"
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" />
</RelativeLayout>
The containing Activity class will replace the Framelayout with Fragment depending on the Fragment selected from the BottomBar View. A simple example
public class Main3Activity extends AppCompatActivity {
private Fragment fragment;
private FragmentManager fragmentManager;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_three_tabs);
BottomBar bottomBar = (BottomBar) findViewById(R.id.bottomBar);
bottomBar.setOnTabSelectListener(new OnTabSelectListener() {
#Override
public void onTabSelected(#IdRes int tabId) {
if(tabId == R.id.tab_home){
fragment = new HomeFragment();
}
if(tabId == R.id.tab_favorite){
fragment = new FavoriteFragment();
}
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.contentContainer, fragment).commit();
});
bottomBar.setOnTabReselectListener(new OnTabReselectListener() {
#Override
public void onTabReSelected(#IdRes int tabId) {
Toast.makeText(getApplicationContext(), TabMessage.get(tabId, true), Toast.LENGTH_LONG).show();
}
});
}
}
Then you can create individual Fragment with their content like below
public class FavoriteFragment extends Fragment {
public FavoriteFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_favorite, container, false
);
}
}

Android - Changing the contentview of the activity of Navigation drawer

I am creating a simple QR scanning app using Navigation drawer to go throw different fragments, for the QR scanning part I am using the ZXing Scanner library.
In one of the fragments, there is a button called "scan", When clicked the following code run
mScannerView = new ZXingScannerView(this);
setContentView(mScannerView); // HERE IS THE begining OF THE PROBLEM
mScannerView.setResultHandler(this);
mScannerView.startCamera();
now in the handleResult method i should write the following code to close the camera.
mScannerView.stopCamera();
setContentView(R.layout.activity_main); // THE PROBLEM OCCUERS HERE
When I run this code I get Binary XML file line #36: Binary XML file line #36: Error inflating class fragment
Any Idea how to solve this ?
Code :
Main Activity:
public class MainActivity extends AppCompatActivity implements FragmentDrawer
.FragmentDrawerListener, ZXingScannerView.ResultHandler {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawerFragment = (FragmentDrawer) getSupportFragmentManager().findFragmentById(R.id.fragment_navigation_drawer);
drawerFragment.setUp(R.id.fragment_navigation_drawer, (DrawerLayout) findViewById(R.id
.drawer_layout), mToolbar);
drawerFragment.setDrawerListener(this);
displayView(0);
}
#Override
public void onDrawerItemSelected(View view, int position) {
displayView(position);
}
private void displayView(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new QRScanerFragment();
title = getString(R.string.title_logout);
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container_body, fragment);
fragmentTransaction.commit();
}
}
public void scan(View view) {
mScannerView = new ZXingScannerView(this);
setContentView(mScannerView);
mScannerView.setResultHandler(this);
mScannerView.startCamera();
}
#Override
public void handleResult(Result result) {
Log.e("QR result", result.getText());
mScannerView.stopCamera();
setContentView(R.layout.activity_main);
}
#Override
protected void onPause() {
super.onPause();
mScannerView.stopCamera();
}
}
as For the XML:
<android.support.v4.widget.DrawerLayout
xmlns:app="http://schemas.android.com/apk/res-auto xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/container_body"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<fragment
android:id="#+id/fragment_navigation_drawer"
android:name="com.bassiouny.androidqrtask.fragments.FragmentDrawer"
android:layout_width="#dimen/nav_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
app:layout="#layout/fragment_navigation_drawer"
tools:layout="#layout/fragment_navigation_drawer" />
A quick look at the source shows that ZXingScannerView is a descendant of the View class. Therefore you should be able to create a layout like this:
<me.dm7.barcodescanner.zxing.ZXingScannerView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:id="#+id/scanner"/>
Then you can create a ScannerFragment that uses this layout as its view:
#Override
public view onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_scanner, container, false);
mScannerView = (ZXingScannerView) view.findViewById(R.id.scanner);
return view;
}
Then, instead of calling setContentView again in your Activity, you can replace the fragment with the ScannerFragment, just as you are with your other fragments:
Fragment fragment = ScannerFragment.newInstance();
FragmentTransaction fragmentManager = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container_body, fragment);
fragmentTransaction.commit();
You may also want to take a look at the sample code provided in the repository. The Fragment in this sample is set up differently, the view is created within the class, instead of in XML. But it may help you utilize any other features provided by ZXingScannerView, as well as handle layout changes.

Destroyed fragment recreated and redestroyed when restarting the app

I'm trying do understand the lifecycle of Fragment.
I have a MainActivity, with a layout including two FrameLayout to load Fragments, one for a top bar with a vertical menu, another one for the content.
When I start the app, an instance of HomeFragment is loaded in the content FrameLayout container. Then when I click on a button in the menu, an instance of SomeFragment replaces it.
When on the SomeFragment content, I click on the device's Home button, and all the visible Fragment (i.e. the TopBarFragment and the SomeFragment) are destroyed and detached from the MainActivity, i.e. onDestroyView, onDestroy and onDetach are called for both.
Now when I restart the app, the TopBarFragment and the SomeFragment are created and destroyed (full lifecycle from onAttach to onDetach) and then the TopBarFragment and the HomeFragment are created, as expected from the code in the MainActivity's onCreate.
Why are the TopBarFragment and the SomeFragment, i.e. the latest visible Fragment before clicking on the device's Home button, recreated and destroyed before executing what's in the MainActivity's onCreate?
Note: in order to test my app I checked the option Don't keep activities in my device's developer options.
MainActivity.java
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment homeFragment = new HomeFragment();
fragmentTransaction.replace(R.id.content_container, homeFragment, "");
Fragment topBarFragment = new TopBarFragment();
fragmentTransaction.replace(R.id.top_bar_container, topBarFragment, "top_bar_fragment");
fragmentTransaction.commit();
}
}
main.xml
<RelativeLayout 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" >
<FrameLayout
android:id="#+id/content_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="44dp" />
<FrameLayout
android:id="#+id/top_bar_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false" />
</RelativeLayout>
TopBarFragment.java
public class TopBarFragment extends Fragment{
private int mSelectedMenuOption = 0;
private LinearLayout mVerticalMenu;
private Boolean mMenuIsOpen = true;
private ImageButton btn_01, btn_02; // there are more
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.top_bar, container, false);
}
#Override
public void onActivityCreated (Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
btn_01 = (ImageButton) getView().findViewById(R.id.btn_01);
btn_02 = (ImageButton) getView().findViewById(R.id.btn_02);
btn_01.setOnClickListener(mButtonClickListener);
btn_02.setOnClickListener(mButtonClickListener);
mVerticalMenu = (LinearLayout) getView().findViewById(R.id.vertical_menu);
toggleMenu(0);
Button btn_menu = (Button) getView().findViewById(R.id.btn_menu);
btn_menu.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// toggle vertical menu
}
});
}
private OnClickListener mButtonClickListener = new OnClickListener()
{
#Override
public void onClick(View v) {
/* ... */
if(!v.isSelected()){
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
switch(v.getId()){
case R.id.btn_01:
Fragment homeFragment = new HomeFragment();
fragmentTransaction.replace(R.id.content_container,homeFragment, "");
fragmentTransaction.commit();
break;
case R.id.btn_02:
Fragment someFragment = new SomeFragment();
fragmentTransaction.replace(R.id.content_container, someFragment, "");
fragmentTransaction.commit();
break;
}
}
}
};
}
SomeFragment
public class SomeFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
((TopBarFragment)getActivity().getSupportFragmentManager().findFragmentByTag("top_bar_fragment")).setSelectedButton(1);
return inflater.inflate(R.layout.some_fragment, container, false);
}
}

How do I add a Fragment to an Activity with a programmatically created content view

I want to add a Fragment to an Activity that implements its layout programmatically. I looked over the Fragment documentation but there aren't many examples describing what I need. Here is the type of code I tried to write:
public class DebugExampleTwo extends Activity {
private ExampleTwoFragment mFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
if (savedInstanceState == null) {
mFragment = new ExampleTwoFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(frame.getId(), mFragment).commit();
}
setContentView(frame);
}
}
...
public class ExampleTwoFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
Button button = new Button(getActivity());
button.setText("Hello There");
return button;
}
}
This code compiles but crashes at start, probably because my FragmentTransaction.add() is incorrect. What is the correct way to do this?
It turns out there's more than one problem with that code. A fragment cannot be declared that way, inside the same java file as the activity but not as a public inner class. The framework expects the fragment's constructor (with no parameters) to be public and visible. Moving the fragment into the Activity as an inner class, or creating a new java file for the fragment fixes that.
The second issue is that when you're adding a fragment this way, you must pass a reference to the fragment's containing view, and that view must have a custom id. Using the default id will crash the app. Here's the updated code:
public class DebugExampleTwo extends Activity {
private static final int CONTENT_VIEW_ID = 10101010;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
frame.setId(CONTENT_VIEW_ID);
setContentView(frame, new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
if (savedInstanceState == null) {
Fragment newFragment = new DebugExampleTwoFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(CONTENT_VIEW_ID, newFragment).commit();
}
}
public static class DebugExampleTwoFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
EditText v = new EditText(getActivity());
v.setText("Hello Fragment!");
return v;
}
}
}
Here is what I came up with after reading Tony Wong's comment:
public class DebugExampleTwo extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addFragment(android.R.id.content,
new DebugExampleTwoFragment(),
DebugExampleTwoFragment.FRAGMENT_TAG);
}
}
...
public abstract class BaseActivity extends Activity {
protected void addFragment(#IdRes int containerViewId,
#NonNull Fragment fragment,
#NonNull String fragmentTag) {
getSupportFragmentManager()
.beginTransaction()
.add(containerViewId, fragment, fragmentTag)
.disallowAddToBackStack()
.commit();
}
protected void replaceFragment(#IdRes int containerViewId,
#NonNull Fragment fragment,
#NonNull String fragmentTag,
#Nullable String backStackStateName) {
getSupportFragmentManager()
.beginTransaction()
.replace(containerViewId, fragment, fragmentTag)
.addToBackStack(backStackStateName)
.commit();
}
}
...
public class DebugExampleTwoFragment extends Fragment {
public static final String FRAGMENT_TAG =
BuildConfig.APPLICATION_ID + ".DEBUG_EXAMPLE_TWO_FRAGMENT_TAG";
// ...
}
Kotlin
If you are using Kotlin make sure to take a look at what the Kotlin extensions by Google provide or just write your own.
public class Example1 extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoFragment fragmentDemo = (DemoFragment)
getSupportFragmentManager().findFragmentById(R.id.frame_container);
//above part is to determine which fragment is in your frame_container
setFragment(fragmentDemo);
(OR)
setFragment(new TestFragment1());
}
// This could be moved into an abstract BaseActivity
// class for being re-used by several instances
protected void setFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
}
}
To add a fragment into a Activity or FramentActivity it requires a
Container. That container should be a "Framelayout", which can be
included in xml or else you can use the default container for that
like "android.R.id.content" to remove or replace a fragment in
Activity.
main.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Framelayout to display Fragments -->
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="#+id/imagenext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="16dp"
android:src="#drawable/next" />
</RelativeLayout>
After read all Answers I came up with elegant way:
public class MyActivity extends ActionBarActivity {
Fragment fragment ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
fragment = fm.findFragmentByTag("myFragmentTag");
if (fragment == null) {
FragmentTransaction ft = fm.beginTransaction();
fragment =new MyFragment();
ft.add(android.R.id.content,fragment,"myFragmentTag");
ft.commit();
}
}
basically you don't need to add a frameLayout as container of your fragment instead you can add straight the fragment into the android root View container
IMPORTANT: don't use replace fragment as most of the approach shown here, unless you don't mind to lose fragment variable instance state during onrecreation process.
For attaching fragment to an activity programmatically in Kotlin, you can look at the following code:
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// create fragment instance
val fragment : FragmentName = FragmentName.newInstance()
// for passing data to fragment
val bundle = Bundle()
bundle.putString("data_to_be_passed", DATA)
fragment.arguments = bundle
// check is important to prevent activity from attaching the fragment if already its attached
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment, "fragment_name")
.commit()
}
}
}
}
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=".ui.MainActivity">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
FragmentName.kt
class FragmentName : Fragment() {
companion object {
fun newInstance() = FragmentName()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// receiving the data passed from activity here
val data = arguments!!.getString("data_to_be_passed")
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
}
}
If you are familiar with Extensions in Kotlin then you can even better this code by following this article.
public abstract class SingleFragmentActivity extends Activity {
public static final String FRAGMENT_TAG = "single";
private Fragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
fragment = onCreateFragment();
getFragmentManager().beginTransaction()
.add(android.R.id.content, fragment, FRAGMENT_TAG)
.commit();
} else {
fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
}
public abstract Fragment onCreateFragment();
public Fragment getFragment() {
return fragment;
}
}
use
public class ViewCatalogItemActivity extends SingleFragmentActivity {
#Override
public Fragment onCreateFragment() {
return new FragmentWorkShops();
}
}
For API level 17 or higher, View.generateViewId() will solve this problem. The utility method provides a unique id that is not used in build time.
This may help you
Defining a Fragment
create xml file for fragment view fragment_abc.xml
<?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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
create fragment ABCFragment.java
import androidx.fragment.app.Fragment;
public class FooFragment extends Fragment {
// The onCreateView method is called when Fragment should create its View object hierarchy,
// either dynamically or via XML layout inflation.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle
savedInstanceState) {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.fragment_abc, parent, false);
}
// This event is triggered soon after onCreateView().
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Setup any handles to view objects here
// EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
}
}
Add frameLayout in your activity
<FrameLayout
android:id="#+id/your_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent">
now in activity, add following method
protected void setFragment() {
// Begin the transaction
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Replace the contents of the container with the new fragment
ft.replace(R.id.fragment_container, new ABCFragment());
// or ft.add(R.id.your_placeholder, new ABCFragment());
// Complete the changes added above
ft.commit();
}
reference : https://guides.codepath.com/android/creating-and-using-fragments#defining-a-fragment

Categories

Resources