Splash
I have main activity UI startup operations that take between 5-10 seconds (that need to be handled on the main UI thread) - so I would like to use a splash screen rather than the default black or non-responsive main UI.
A good solution to the splash screen is provided below
which is to first set setContentView(R.layout.splash),
then do the necessary main UI processing (on UI thread but with main view that is not visible)
and when that is ready show setContentView(R.layout.main)
Android Splash Screen before black screen
Splash with Fragments
I'm also using fragments, which normally require setContentView(R.layout.main) to be called before fragment instantiation - so that the fragment manager could find the view stubs in R.layout.main to inflate the fragments into (strictly speaking view stubs are a different thing).
But I cannot call setContentView(R.layout.main) before creating the fragments, because that replaces the splash screen with the (not-yet-ready) main screen.
My fear is that what I want to do cannot be done?
Unfortunately, there is no overload like fragmentTransaction.add(viewNotViewId, fragment);
Almost-Answer
Here's all but the key, which is that setContentView is called before the fragment transactions:
How do I add a Fragment to an Activity with a programmatically created content view
You could try replacing your fragments in your FragmentActivity, here is the idea partially coded:
Suppose you have your fragments layout like this (main.xml):
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal">
<LinearLayout android:id="#+id/waiting" ...>
</LinearLayout>
<!-- hidden layout -->
<LinearLayout>
<LinearLayout android:id="#+id/layout_list_items" ...>
</LinearLayout>
<LinearLayout android:id="#+id/layout_detail" ...>
</LinearLayout>
</LinearLayout>
</LinearLayout>
And your FragmentActivity like this:
public class FragmentsActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
Fragment fragA = new WaitingTransaction();
FragmentTransaction fragTrans = this.getSupportFragmentManager().beginTransaction();
fragTrans.add(R.main.waiting, fragA);
fragTrans.commit();
}
private void afterProcessing(){
//show hidden layout and make the waiting hidden through visibility, then add the fragment bellow...
FragmentTransaction fragTrans = this.getSupportFragmentManager().beginTransaction();
fragTrans.add(R.main.layout_list_items,
new FragmentList());
fragTrans.replace(R.main.layout_detail,
new FragmentB());
fragTrans.commit();
}
}
Try this code without calling any setContentView
fragmentTransaction.add(android.R.id.content, Fragment.instantiate(MainActivity.this, SplashFragment.class.getName()));
The main approach here is placing fragment in view with id android.R.id.content which is always present before any layout is inflated via setContentView
Related
I'm struggling with something really simple. ( or at least this was my idea.. )
I would need to put a simple button on top of a map inside a viewpager.
Actually I'm creating the supportmapfragment programmatically and adding it to the crated viewpager adapter .
ViewPagerAdapter adapter = new ViewPagerAdapter
(getSupportFragmentManager());
mapFrag = new SupportMapFragment();
mapFrag.getMapAsync(this);
adapter.addFragment(mapFrag, getString(R.string.maptab));
now... to put a button on top I would need the view from supportmapfragment so I can push up "my button_" via addview.
I cannot understand how to retrieve the view without extending the class for supportmapfragment but this would need me to create a custom supportmapfragment class.
any idea?
after suggestion: I made a test with a relative layout :
<fragment
android:id="#+id/rlMap"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</fragment>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Button 1"/>
this make button appear for a second (before map load) then being uncovered by map . even putting button inside the fragment sort same effect
Even if you try and put the button over the fragment's view, you will still need to set a click listener and do some logic when it's pressed. I think that would make the existing code a bit messy, passing a responsibility of the fragment (registering the button click listener) to the activity.
What I would do if I were you would be create a new Fragment with some ConstraintLayout that contains the underlying map and the button (but does not extend SupportMapFragment). It would be a wrapper fragment where you can also handle the button with its events, and whatever would be needed more.
I create custom view and use it in some xml activity then set android:onClick="buttonOnClick". I defined buttonOnClick as public and write it in its activity and set tools:context.
Activity.java
public void buttonOnClick(View view) {
validate(view);
}
layout.xml
<LinearLayout 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"
...
tools:context="com.test.myapp.Activity">
<com.test.myapp.GifImageViewComp
....
android:onClick="buttonOnClick" />
it's working on Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP but in other OS version, custom view xml onclick attribute try to find handler from view class instead of activity.
I don't want use implementation of onClick or setOnClickListener on every view, i want use onClick in layout of activity
It's just not clear the relationship between a button in your xml and
a method in your activity that reacts to the click events unless you
explicitly see it defined in your Java file. With the android:onClick
approach you can even forget that you have a button in your layout or
which is the method that is handling its onClick event.
Source
You should use OnClickListener instead of android:onClick .
Interface definition for a callback to be invoked when a view is
clicked.
This method takes the reference to the Listener and registers a callback to be invoked when the View is clicked.
FYI
Make sure you set android:clickable="true" in XML . you should specify this attribute .
<com.test.myapp.GifImageViewComp
android:clickable="true"
android:onClick="buttonOnClick" />
I have started coding and I really like it, I have been on/off on diffrent project (to learn diffrent things) But now i got a problem, I "app"reciate all the help i can get.
I am using the navigation drawer and got three fragments installed. I can navigate through the navigation drawer and select a fragment and it loads on my screen. But when i start my app the screen is just white and the navigation drawer is on the left and i can pick a fragment. Is it possible to have a fragment on my "home screen" so when I start the app there is a fragment already placed on the screen BUT! when i chosse another fragment in the navigation drawer i would like to have my fragment who loaded at the beginning to disappear. Otherwise both fragments will show on eachother (Text on text). Maybe to have the temporary fragment to "finish" itself somehow. Please look at my imgur image to get my idea.Imgur image press here to view
Here is a generic solution on how to use the FragmentManager. It should give a good idea on how to display a Fragment. Besides that you could include a static Fragment in your layout. It's up to you how to approach it.
So the FragmentManager solution looks like this:
YourActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fragmentManager = getFragmentManager();
Fragment fragment = AnyFragment.instantiate(this, AnyFragment.class.getName());
fragmentManager.beginTransaction().add(R.id.fragment_placeholder, fragment).addToBackStack(null).commit();
}
The target id is defined in your activity 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">
<FrameLayout
android:id="#+id/fragment_placeholder"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"></FrameLayout>
</LinearLayout>
Later if you want to replace the current Fragment you can use the remove and add method of the FragmentManager (the replace method is kinda buggy).
Fragment currentFragment = fragmentManager.findFragmentById(R.id.fragment_placeholder))
fragmentManager.beginTransaction().remove(currentFragment).add(R.id.fragment_placeholder, yourNewFragment).addToBackStack(null).commit();
My school assignment has an activity that contains a ListFragment and a Fragment. The MainActivity creates the ListFragment, and then each item on the list should open the regular Fragment that just contains a picture, and then when I click on the picture it should go back to the ListFragment.
In all cases, I call the fragments using this code (edited for the specific case of course):
Fragment fragTwo = new FragmentTwo();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_place, fragTwo);
ft.addToBackStack(null);
ft.commit();
It calls the fragments OK, except that the second fragment will appear OVER the ListFragment, and I can still select things from the list while the second fragment is open. Do I need to create a new fragment object every time I navigate? And how do I disable/enable a fragment from it's own onclick listener?
main_activity.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" >
<fragment
android:name="com.example.w0068332.fragmentstest.FragmentOne"
android:id="#+id/fragment_place"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
1- Yes you need to create a fragment for each item.
Bundle arguments = new Bundle();
arguments.putInt(FragmentTwo.ARG_ITEM_ID,R.drawable_pic);
FragmentTwo fragment = new FragmentTwo();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.item_detail_container, fragment)
.commit();
I suppose that you display pictures from resources
2- To disable selection from ListFragment while displaying the second one.
In the parent layout of the second fragment you have to add background and make it clickable as below:
android:background="#color/white"
android:clickable="true"
3- To navigate back for the ListFragment add a click listener for the ImageView and onClick call onBackPressed of the Activity:
getActivity().onBackPressed();
you can also have a look on a template from Android studio for Master and details activity
This seems to be such a fundamental question that I'm embarrassed to ask it, but I'm so frustrated by my Fragment learning curve that I'll expose my ignorance.
An example in a textbook that cuts a lot of corners that make expanding them difficult, if they even work, had no button to click; MainActivity simply loaded FragmentA. OK, keep it basic. I get that.
So I added a button to MainActivity to click to load FragmentA, but the button shows on the FragmentA screen, sort of like this (not an actual screen shot, but close):
How do I prevent that? Should I use a second Activity instead of a Fragment? Since this endeavor is to be utilized in a much larger project, I don't want to do anything considered not best practice. I realize that the main use of Fragment is to enable side-by-side "screens" on devices that are large enough. That's not what I want to do, but it IS possible to accomplish what I want with a Fragment, isn't it?
MainActivity.java
public class MainActivity extends Activity {
#Override protected void onCreate(Bundle savedInstanceState)
{
super.onCreate( savedInstanceState);
setContentView(R.layout.activity_main);
}
public void btnLoadFragmentAByClick(View view)
{
FragmentA fragmentA;
fragmentA = new FragmentA();
FragmentTransaction ft ;
ft = getFragmentManager().beginTransaction();
ft.replace(R.id.layout_container, fragmentA);
ft.addToBackStack("example");
ft.commit();
}
}
FragmentA.java
public class FragmentA extends Fragment
{
#Override
public View onCreateView(LayoutInflater _inflater,
ViewGroup _container,
Bundle _savedInstanceState)
{
return _inflater.inflate(R.layout.fragment_a,
_container,
false);
}
}
activity_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"
tools:context =".MainActivity" >
<LinearLayout
android:id ="#+id/layout_container"
android:orientation ="vertical"
android:layout_width ="wrap_content"
android:layout_height="wrap_content"
>
</LinearLayout>
<Button
android:id ="#+id/btnLoadFragmentA"
android:text ="Load Fragment A"
android:onClick="btnLoadFragmentAByClick"
android:layout_width ="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
fragment_a.xml
<RelativeLayout
xmlns:android ="http://schemas.android.com/apk/res/android"
android:layout_width ="match_parent"
android:layout_height ="match_parent" >
<TextView
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="Layout for fragment A"
android:textAppearance ="?android:attr/textAppearanceLarge"
>
</TextView>
</RelativeLayout>
EDIT
I realize that I could hide the MainActiviy button (and any other objects) before loading FragmentA and show them after returning, but I was hoping for a one-or-two-line "fix".
How do I prevent that?
Well, to some extent, you don't, insofar as this has nothing to do with fragments.
Your activity_main.xml has the Button floating over top of the LinearLayout (???) that you are using for your fragment container. If you do not want the Button floating over top of the fragment container, then fix the layout file to not have the Button floating over top of the fragment container.
I realize that I could hide the MainActiviy button (and any other objects) before loading FragmentA and show them after returning, but I was hoping for a one-or-two-line "fix".
The typical solution for full-UI replacement using fragments is to have everything in fragments. Your replace() would replace your original fragment with a replacement. So, in this case, your Button would be managed by one fragment, and clicking the Button would replace() that fragment with another fragment. Given that your FragmentTransaction has addToBackStack(), pressing BACK would get rid of the replacement fragment and return you to your Button fragment.