How to add width and height of fragment programatically? - android

I want to add a fragment to MainActivity but when I am adding a fragmnet to it, it is covering the full width and height of main activity. So how to set the width and height of fragment to wrap content programatically, not using XML.
Here is the code of what I have do so far:
MainActivity.xml
<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:id="#+id/rekl"
android:layout_height="match_parent"
tools:context="com.example.ankit.fragment2.MainActivity">
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Fragment3 f=new Fragment3();
FragmentManager m=getFragmentManager();
FragmentTransaction t=m.beginTransaction();
t.add(R.id.rekl,f,"Frag");
t.commit();
}
}

Related

How to make a transition from one fragment to another? [duplicate]

I am currently trying to create an app having a splash screen, a login screen and a register screen.
The only way to achieve exactly what I need is through fragments. Though when I try to transition from the splash screen to the login fragment the text view which was part of the splash screen remains. The same happens after transitioning from the login fragment to the register fragment as well as from the register fragment back to the login fragment. It is important to note that there is no issue during transitioning between login and register or between register and login - except the fact that the edit text stays there.
My MainActivity.java
public class StartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
}
#Override
public void onBackPressed(){
Toast.makeText(getApplicationContext(), "Back button is disabled", Toast.LENGTH_SHORT).show();
}
}
My layout for MainActivity
<?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"
tools:context=".StartActivity"
android:background="#mipmap/background">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/viewpagerstart"
android:layout_centerInParent="true"
android:name="com.example.distributedsystemsui.SplashFragment">
</fragment>
</RelativeLayout>
The SplashScreen.java
public class SplashFragment extends Fragment {
LinearLayout linearLayout;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_splash, container, false);
linearLayout = (LinearLayout) view.findViewById(R.id.f_linearsplash);
Animation animation_fadein = AnimationUtils.loadAnimation((StartActivity)getActivity(), R.anim.fade_in);
linearLayout.startAnimation(animation_fadein);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_enter_left, R.anim.slide_exit_left,
R.anim.slide_enter_right, R.anim.slide_exit_right);
LoginFragment loginFragment = LoginFragment.newInstance();
ft.replace(R.id.viewpagerstart, loginFragment);
ft.commit();
}
}, 3000);
return view;
}
}
And the layout for the SplashScreen fragment.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".LoginFragment"
android:background="#color/Tranparent"
android:id="#+id/frame_splash">
<LinearLayout
android:id="#+id/f_linearsplash"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/f_splashlogo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="70dp"
android:background="#FFFFFF"/>
<TextView
android:id="#+id/f_splashtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/app_name"
android:layout_gravity="center_horizontal"
android:layout_marginTop="100dp"
android:background="#FFFFFF"/>
</LinearLayout>
</FrameLayout>
All my search led back to nothing.
I can only assume that either the below contained in the MainActivity.xml creates a confusion (which I tried to change but no luck):
android:name="com.example.distributedsystemsui.SplashFragment"
or that I am doing a mistake in the SplashScreen.java that I cannot locate, even though I tried for more than 5 hours to make it work.
The problem is that you cannot replace fragments added via the <fragment> tag.
Instead, you should either:
1) Switch to FragmentContainerView, which was added in Fragment 1.2.0. It does not suffer from the same issue as the <fragment> tag and lets you do replace operations without issues:
<?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"
tools:context=".StartActivity"
android:background="#mipmap/background">
<androidx.fragment.app.FragmentContainerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/viewpagerstart"
android:layout_centerInParent="true"
android:name="com.example.distributedsystemsui.SplashFragment">
</androidx.fragment.app.FragmentContainerView>
</RelativeLayout>
2) Use a FrameLayout in your layout and manually add the SplashFragment in your activity (this is essentially what FragmentContainerView does for you):
<?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"
tools:context=".StartActivity"
android:background="#mipmap/background">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/viewpagerstart"
android:layout_centerInParent="true">
</FrameLayout>
</RelativeLayout>
which means you need to add the SplashFragment manually:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.viewpagerstart, new SplashFragment())
.commit()
}
}
I think it is better to do the fragment transactions from your activity instead of doing it from your fragment. You might consider having functions in your MainActivity as follows.
public class StartActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
}
public void goToLoginFragment() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_enter_left, R.anim.slide_exit_left,
R.anim.slide_enter_right, R.anim.slide_exit_right);
LoginFragment loginFragment = LoginFragment.newInstance();
ft.replace(R.id.viewpagerstart, loginFragment);
ft.commit();
}
public void goToRegisterFragment() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_enter_left, R.anim.slide_exit_left,
R.anim.slide_enter_right, R.anim.slide_exit_right);
LoginFragment registerFragment = RegisterFragment.newInstance();
ft.replace(R.id.viewpagerstart, registerFragment);
ft.commit();
}
#Override
public void onBackPressed(){
Toast.makeText(getApplicationContext(), "Back button is disabled", Toast.LENGTH_SHORT).show();
}
}
And then from your SplashFragment call the function that is defined in your activity.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
((MainActivity) getActivity()).goToLoginFragment();
}
}, 3000);
I hope that solves the problem.

How to show fragment only when button pressed?

I'm trying to show an image below a button only after the button has been pressed. My problem is that the fragment is shown immediately when the app is started and not only after the button has been pressed.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void say_hello(View view){
Fragment fragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment2, fragment).commit();
}
}
public class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.news_articles, container, false);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:orientation="vertical"
android:layout_height="fill_parent"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center_vertical"
android:text="PRESS THIS"
android:id = "#+id/test_button"
android:background="#drawable/test_button"
android:onClick="say_hello"
/>
<fragment
android:id="#+id/fragment2"
android:name="com.example.tic_tac_toe.ExampleFragment"
android:layout_width="match_parent"
android:layout_height="643dp" />
</LinearLayout>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/cool_dog">
</ImageView>
I'm guessing the fragment shows up when the app is started because of the name I give to the fragment in the XML, but the fragment needs a name otherwise I only get error. How do I get the fragment to display nothing before I have clicked the button?
Instead of using <fragment /> view in your xml, you can use Framelayout and add your fragment to this Framelayout on button click using the following code -
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.mainframe, fragment);
transaction.commit();
Where mainframe is the id of Framelayout.
You can try doing this
android.app.Fragment fragment = getActivity().getFragmentManager().findFragmentByTag("YOUR_FRAGMENT_TAG");
getActivity().getFragmentManager().beginTransaction().hide(fragment);
inside your click event.

Android - access fragment view from fragment container programatically

In MainActivity's onCreate, I replaced the FrameLayout fragment container in its xml layout with a DragSelectRecyclerView in MainFragment's xml layout using FragmentManager. The following code shows this:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, new MainFragment())
.commit();
}
MainActivity's xml:
<android.support.design.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="com.gra.app.activities.MainActivity">
<FrameLayout
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="?attr/actionBarSize" />
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior=".utilities.AppBarLayoutBackgroundAlphaBehavior">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar" />
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
MainFragment's xml:
<com.afollestad.dragselectrecyclerview.DragSelectRecyclerView 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/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:dsrv_autoScrollEnabled="true"
app:dsrv_autoScrollHotspotHeight="56dp"
tools:context="com.gra.app.fragments.MainFragment" />
Is there any way to programmatically access an instance of DragSelectRecyclerView through FrameLayout?
The reason for this is I need to make the AppBarLayout inside MainActivity's xml dependent on MainFragment's DragSelectRecyclerView so I can fade the AppBarLayout in/out based on
DragSelectRecyclerView.getVerticalScrollbarPosition()
through
CoordinatorLayout.Behavior<AppBarLayout>
Is this possible or should I just move the DragSelectRecyclerView inside MainActivity's xml?
I would suggest you to have a public method in MainFragment -
public float getVerticalScrollbarPosition(){
return DragSelectRecyclerView.getVerticalScrollbarPosition();
}
Update MainActivity's onCreate method to this -
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainFragment mainFragment = new MainFragment();
getFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, mainFragment)
.commit();
}
Now within the MainActivity, you can access the method anywhere to get the value and fade the AppBarLayout in/out accordingly -
mainFragment.getVerticalScrollbarPosition();
This is how the communication between fragments and activity should be handled - https://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
You could set the fragment directly in the xml layout of the main activity like
<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">
<fragment android:id="#+id/fragment"
android:name="some.package.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
And then get the instance of DragSelectRecyclerView in the onCreate method of your activity by
DragSelectRecyclerView recyclerView = (DragSelectRecyclerView) findViewById(R.id.recyclerView)
Or you just set the DragSelectRecyclerView from your Fragment into your Activity:
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
DragSelectRecyclerView dragSelectRecyclerView = (DragSelectRecyclerView) getView().findViewById(R.id.recyclerView);
Activity activity = getActivity();
if (activity != null && activity instanceof MainActivity) {
((MainActivity) activity).setDragSelectRecyclerView(dragSelectRecyclerView);
}
}
In both cases make sure you reset the variable after you fragment is gone.
#Override
public void onDestroyView() {
super.onDestroyView();
Activity activity = getActivity();
if (activity != null && activity instanceof MainActivity) {
((MainActivity) activity).setDragSelectRecyclerView(null);
}
}
you can try setting a tag in the fragment transaction and then retrieve the fragment and its view by the tag you set during the transaction.
you can do it like this:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, new MainFragment(),"tag") //Adding tag here
.commit();
}
and then later you can retreive the recyclerview inside that fragment by:
View fragmentView = getFragmentManager().findFragmentByTag("tag").getView();
DragSelectRecyclerView recyclerView = (DragSelectRecyclerView)fragmentView.findViewById(R.id.recyclerView) //use the view
but View fragmentView = getFragmentManager().findFragmentByTag("tag").getView(); may return null based on the state of the fragment's state. so you need to look out for that.

FragmentManager gives me NPE

I'm checking fragments for the first time and I created a LinearLayout with a FrameLayout within and for my layout-sw600dp a LinearLayout with 2 FrameLayouts.
The one has an id of "main" and the other is "details".
The error I get is :
Caused by: java.lang.NullPointerException
at android.app.BackStackRecord.doAddOp(BackStackRecord.java:395)
at android.app.BackStackRecord.add(BackStackRecord.java:385)
at mes.fallstudio.tvfall.MainActivity.onCreate(MainActivity.java:28)
where line 28 is the last line here:
public class MainActivity extends AppCompatActivity {
private android.support.v4.app.Fragment mainFragment;
private android.app.Fragment detailsFragment;
private Boolean isDualPane = false;
private android.support.v4.app.FragmentManager fm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
mainFragment = fragmentManager.findFragmentById(R.id.main);
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.main, mainFragment).commit();
}
}
XML layout files :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<FrameLayout
android:id="#+id/details"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
this is for layout-sw600dp and the same without the 2nd FrameLayout ( details) for the xml file for the layout folder.
I'm extending AppCompatActivity if this helps.
Thanks you
AppCompatActivity uses getSupportFragmentManager() instead of getFragmentManager().
Reference: https://developer.android.com/reference/android/support/v7/app/AppCompatActivity.html
EDIT:
In your code you try to get mainFragment from the XML layout. However, you do not define it there. You can either instantiate mainFragment in your code:
mainFragment = new MainFragment();
Or define it in your XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="mes.fallstudio.tvfall.MainFragment"
android:id="#+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/details"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
In the latter case you don't need to use the FragmentManager at all in your code unless you need to manipulate the fragments at run time.
In both cases you also need the actual fragment:
public class MainFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.main_fragment, container, false);
}
}

PreferenceFragment not shown when using ActionBarActivity

I have a PreferenceFragment and it can be shown inside an Activity. However, when I switch the Activity to an ActionBarActivity, the fragment is not shown. (I can only see an action bar and a blank white screen below.) The theme I am using is Theme.AppCompat.Light, therefore I need to use ActionBarActivity in order to display the ActionBar.
Here is my original code:
public class SettingsActivity extends Activity { // later changed to extend ActionBarActivity
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content
getFragmentManager().beginTransaction().
replace(android.R.id.content, new SettingsFragment()).commit();
}
}
I'm extending ActionBarActivity and my PreferenceFragment works.
I think you need to call setContentView() on your Activity, to have an activity layout in which the fragment will be loaded.
activity_preference_layout.xml
<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"
tools:context="your.package.SettingsActivity">
<include layout="#layout/toolbar"/>
<FrameLayout
android:id="#+id/preference_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
Then your Activity should be something like:
public class SettingsActivity extends ActionBarActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preference_layout);
getFragmentManager().beginTransaction().
replace(R.id.preference_container, new SettingsFragment()).commit();
}
}
Note that I've replaced android.R.id.content with R.id.preference_container, which is the frame defined in the layout above.

Categories

Resources