Android Fragment does not go to second fragment - android

The problem is that when I click one element from the list is does not go to detail fragment view..but it work fine when it goes to landscape mode.Please tell me how can I go from list view to detail view by staying in portrait mode.
This is my list class
public class HadithList extends ListFragment
{
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
Log.d("ERROR", "In hadith list");
String[] strHadith = new String[] {"Hadith one","Hadith two","Hadith three","Hadith four"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity()
,android.R.layout.simple_list_item_1,strHadith);
setListAdapter(adapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
String item = (String) getListAdapter().getItem(position);
HadithDetail hadithDetail = (HadithDetail) getFragmentManager().findFragmentById(R.id.hadith_detail);
//HadithDetail hadithDetail1 = (HadithDetail) getFragmentManager().findFragmentByTag("Details");
FragmentTransaction ft = getFragmentManager().beginTransaction();
Toast.makeText(getActivity(), "Selected "+position, Toast.LENGTH_SHORT).show();
//if(hadithDetail != null && hadithDetail.isInLayout())
hadithDetail.setText(getDetails(item));
ft.replace(R.id.hadith_list, hadithDetail);
ft.commit();
}
private String getDetails(String topic)
{
if(topic.toLowerCase().contains("one"))
{
return "Here is hadith 1 detail";
}
if(topic.toLowerCase().contains("two"))
{
return "Here is hadith 2 detail";
}
if(topic.toLowerCase().contains("three"))
{
return "Here is hadith 3 detail";
}
if(topic.toLowerCase().contains("four"))
{
return "Here is hadith 4 detail";
}
return "Cannot find detail";
}
}
This is my Detail class
![public class HadithDetail extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
Log.d("ERROR", "In hadith detail");
View view = inflater.inflate(R.layout.hadith_detail,container,false);
return view;
}
public void setText(String txt)
{
TextView view = (TextView) getView().findViewById(R.id.txtDetail);
view.setText(txt);
}
}][1]
Activity Main
<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="horizontal" >
<fragment
android:id="#+id/hadith_list"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
class="com.example.hadith_app.HadithList"
/>
</LinearLayout>
Detail Layout
<TextView
android:id="#+id/txtDetail"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal|center_vertical"
android:layout_marginTop="20dip"
android:text="Hadith 1 Detail"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="30sp"
/>
</LinearLayout>
Activity_Main.xml (Land*strong text*)
<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="horizontal" >
<fragment
android:id="#+id/hadith_list"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
class="com.example.hadith_app.HadithList"
/>
<fragment
android:id="#+id/hadith_detail"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="match_parent"
class="com.example.hadith_app.HadithDetail"
/>
</LinearLayout>

First: FragmentTransaction.replace() takes the ID of a ViewGroup, not of the fragment. You need to have a ViewGroup (such as FrameLayout) in your layout XML that acts as a container for your fragments.
Second: A fragment declared statically in an XML layout cannot be removed. You need to add it programmatically when the activity is created. You can do this like so:
public class MyActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
// savedInstancState is null on the first time onCreate() runs
Fragment f = new HadithList();
getFragmentManager().beginTransaction().add(R.id.fragment_container, f).commit();
}
}
}

I believe you should read those two links first ! to see an example of how to implement the List and Details
http://www.vogella.com/articles/AndroidFragments/article.html
http://developer.android.com/guide/components/fragments.html
Some notes:
1) First of all ,you should commit your transaction in the activity.
2) Here ft.replace(R.id.hadith_list, hadithDetail); you are trying to replace your static fragment with another one. It doesn't work like this.
(I think you should get an error when you are doing that but I am not sure).
3) Dynamic Fragments should be added in a FrameLayout. And not in the sameLayout as your List.
Anyway, just check the above Links which explain very well how you should implement the List and Details Fragments and I am sure you will find what is wrong.
I can't provide a complete example because for sure it will not be as good as the examples you will find in the above tutorials.

Related

Make a view inside a frame an ontouchlistener

How can I create an onTouchListener for a frame that only houses a fragment? I don't need to inflate an activity_main file as it will already be displayed by the time this fragment is called. If I try to inflate the frame itself it throws a "expected resource of type layout" error.
The fragment will be activated when a user touches a button and the fragment should open in the frame. The frame also needs to be able to listen to touch events.
This is what my Fragment and onCreateView for the fragment looks like right now:
public class TeacherFragment extends Fragment {
public final String TAG = getClass().getSimpleName();
public void onAttach(Activity myActivity){
Log.v(TAG, "in TeacherFragment - onAttach, activity is: " + myActivity);
super.onAttach(myActivity);
}
/**
* This method will only be called once when the retained
* Fragment is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retain this fragment across configuration changes.
setRetainInstance(true);
}
/**
* This method will be called only when
* Fragment is attached and ready to display the view.
*/
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle SavedInstanceState){
if(container == null) {
Log.v(TAG, "container is null. No need to inflate.");
return null;
}
View v = container.findViewById(R.id.assignment_view);
v.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG, "onShortPress: " + event.toString());
Toast.makeText(getView().getContext(), "Testing Short click", Toast.LENGTH_SHORT).show();
return true;
}
public void onLongPress(MotionEvent event) {
Log.d(TAG, "onLongPress: " + event.toString());
Toast.makeText(getView().getContext(), "Testing Long click", Toast.LENGTH_SHORT).show();
}
});
return v;
} //end onCreateView
}
Here is my activity_main. I am trying to use the assignment_view frame only for this Fragment.
<?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"
android:id="#+id/main_layout"
android:baselineAligned="false">
<FrameLayout
android:id="#+id/main_menu_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#FF0000"
android:layout_weight=".3">
</FrameLayout>
<FrameLayout
android:layout_width="8dp"
android:layout_height="match_parent"
android:background="#000000">
</FrameLayout>
<FrameLayout
android:id="#+id/assignment_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00BBFF"
android:layout_weight="8">
</FrameLayout>
</LinearLayout>
You should only use inflate() on a file. One that's in your "layout" folder. This is what the error message is telling you. Without spending a lot of time looking at this, you probably want this
View v = findViewById(R.id.assignment_view);
As far as inflating your "activity_main.xml" file, it's probably better to inflate it here than rely on what was inflated in the calling activity.

Trouble editing TextView within Fragment

So I am still fairly new to working with Android Studio and everything in it. I have been stuck on trying to get fragments to communicate directly with each other. Here I'm simply just trying to set the TextView text element within one of my fragments. I have looked for hours and tried a lot, but I'm not sure what to do. Also, I am implementing my fragments through code in a FrameLayout.
Here is my fragment whose text value I'm trying to edit:
public class ReceivingFrag extends Fragment {
TextView sender;
public void updateText(String text) {
sender.setText(text);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag_sender, container, false);
sender = (TextView) v.findViewById(R.id.sender);
return v;
}
}
I believe my root problem is that getView() and sender both return Null. I also understand that fragments are not technically views, but rather aid in the layout of views and ViewGroups. Any help is appreciated.
Not sure if it helps, but this is the method that calls the updateText() method within the ReceivingFrag class.
public void sendText(String text){
ReceivingFrag frag = new ReceivingFrag();
getSupportFragmentManager().beginTransaction().add(R.id.receiving_container, frag).commit();
getSupportFragmentManager().executePendingTransactions()
frag.updateText(text);
}
**Edit:
This is my MainActivity class that is calling and creating the Fragment:
public class MainActivity extends AppCompatActivity implements SendingFragment.TextClicked {
private static final String TAG = MainActivity.class.getSimpleName();
public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] myStringArray = {"Hello", "Nice To See You", "Bye"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, myStringArray);
ListView listView = (ListView) findViewById(R.id.mobile_list);
listView.setAdapter(adapter);
sendText("Hello");
}
#Override
public void sendText(String text){
ReceivingFrag frag = new ReceivingFrag();
getSupportFragmentManager().beginTransaction().add(R.id.receiving_container, frag).commit();
getSupportFragmentManager().executePendingTransactions();
frag.updateText(text);
}}
**Edit 2:
This is the MainActivity layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/apk/tools"
xmlns:tools2="http://schemas.android.com/tools"
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"
android:weightSum="1">
<EditText android:id="#+id/edit_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="#string/edit_message"
android:layout_weight="1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="sendMessage"
android:text="#string/button_send"/>
</LinearLayout>
<ListView android:id="#+id/mobile_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="#+id/receiving_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></FrameLayout></LinearLayout>
And this is the layout for the Fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/sender"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/frag_sender"
android:background="#color/gray"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"/></LinearLayout>
Solution:
So as mentioned below, the runtime error was fixed by adding
#Override
protected void onResume() {
super.onResume();
sendText("hello");
}
to the MainActivity class. After reading from https://developer.android.com/guide/components/fragments.html#Lifecycle
I think the statement
"Once the activity reaches the resumed state, you can freely add and remove fragments to the activity. Thus, only while the activity is in the resumed state can the lifecycle of a fragment change independently."
best explains the situation and why the error initially occurred.
If you instead put the sendText() in your onResume() like this,
#Override
protected void onResume() {
super.onResume();
sendText("Hello");
}
It will not give you the Null Pointer Exception. The fragment is still null when you call on it from onCreate().
Change your Fragment to this:
public class ReceivingFrag extends Fragment {
private TextView sender;
public void updateText(String text) {
sender.setText(text);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag_sender, container, false);
sender = (TextView) v.findViewById(R.id.sender);
return v;
}
}
and in your activity, before calling the updateText method, make sure the fragment transaction has executed by doing:
public void sendText(String text){
ReceivingFrag frag = new ReceivingFrag();
getSupportFragmentManager().beginTransaction().add(R.id.receiving_container, frag).commit();
getSupportFragmentManager().executePendingTransactions();
frag.updateText(text);
}

Android construct for chaining fragments together

I'm looking to create a small flash card type element for my app. I've looked at several solutions namely the FragmentStatePagerAdapter and it's parent the FragmentPagerAdapter. Neither of these solve the problem I want to solve. They deal with listviews of fragments. I want to have a list of fragments that when I hit a button I move to the next one fragment in the list until I'm all done.
I've got all the saving the data part of it solved. I just cannot figure out how to chain my fragments together.
To be explicit, what I'm looking for is:
a->b->c->d->done and go back to activity or a finished fragment.
The user would obviously use a button to progress from fragment to fragment.
I chose fragments because I figured that would be the easiest. I'm not opposed to activities, but my problem is still largely the same.
I've tried implementing the FragmentPager stuff, but as I said it didn't suite my needs.
How dynamic are the fragments you are making? If there's a set amount of interchangeable elements, you can try creating a delegate function in your main activity that opens fragments depending on a set of parameters. Better still, you make your fragments modular so that you only have a few fragments with different states based on what you give them.
public void onCardWithIdSelected(int id, String param1, String param2, ...) {
Fragment fragment = NULL;
if(id == 0) {
fragment = cardFragment.newInstanceFromParams(param1, param2, ...); //this will pass the parameters onto the desired fragment
}
else if(id == 1) {
fragment = cardFragment.newInstanceFromParams(param1, param2, ...); //this will pass the parameters onto the desired fragment
}
else if(id == 2) {
fragment = cardFragment.newInstanceFromParams(param1, param2, ...); //this will pass the parameters onto the desired fragment
}
//and so on...
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.content_frame, fragment);
transaction.addToBackStack(null); //only do this if you don't want users to be able to go back
// Commit the transaction
transaction.commit();
}
Then whenever you want to move to a different fragment from one, you just call this function on the main activity with your desired parameters.
I figured out how to do this with a rather simple solution:
I have my activity which has some variables so that it knows what fragment it is on, along with that it inflates a layout with a framelayout and uses fragmentmanager transactions to replace given the fragment number we are on. Then I have a parcelable class that defines the flashcard that is passed to each fragment upon instantiation. On the activity's layout I have 3 buttons, "check", "correct", "incorrect" which, using View.GONE/View.VISIBLE am able to give the UI experience I want. On the click of the "correct"/"incorrect" we start a transaction and move down the list to the next card.
The code:
/**
* The activity
*/
public class VocabTestActivity extends Activity {
private int mWordsCorrect = 0;
private int mWordsIncorrect = 0;
private int mCurrentPosition = 0;
private ArrayList<Fragment> mCards = new ArrayList<Fragment>();
private final int FLAG_TOTAL_CARDS = 5;
private GrammarDataSource mDataSource;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_practice);
final Button buttonCheck = (Button) findViewById(R.id.buttonCheckWordPractice);
final Button buttonCorrect = (Button) findViewById(R.id.buttonCorrectWordPractice);
final Button buttonIncorrect = (Button) findViewById(R.id.buttonIncorrectWordPractice);
final TextView textViewProgressBar = (TextView) findViewById(R.id.textViewProgressBarPractice);
this.mDataSource = new GrammarDataSource(this);
this.initializeCards();
buttonCheck.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
buttonCheck.setVisibility(View.GONE);
buttonCorrect.setVisibility(View.VISIBLE);
buttonIncorrect.setVisibility(View.VISIBLE);
}
});
buttonCorrect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mWordsCorrect++;
getFragmentManager().beginTransaction().replace(
R.id.practice_frame,
mCards.get(mCurrentPosition++)
).commit();
buttonCheck.setVisibility(View.VISIBLE);
buttonCorrect.setVisibility(View.GONE);
buttonIncorrect.setVisibility(View.GONE);
textViewProgressBar.setText(getString(R.string.practice_progress_bar, mCurrentPosition, FLAG_TOTAL_CARDS));
}
});
buttonIncorrect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mWordsIncorrect++;
getFragmentManager().beginTransaction().replace(
R.id.practice_frame,
mCards.get(mCurrentPosition++)
).commit();
buttonCheck.setVisibility(View.VISIBLE);
buttonCorrect.setVisibility(View.GONE);
buttonIncorrect.setVisibility(View.GONE);
textViewProgressBar.setText(getString(R.string.practice_progress_bar, mCurrentPosition, FLAG_TOTAL_CARDS));
}
});
}
private void initializeCards() {
for(VocabWord v : this.mDataSource.selectFlashCards(FLAG_TOTAL_CARDS)) {
VocabTestFragment frag = VocabTestFragment.newInstance(new ParcelableWord(v));
mCards.add(frag);
}
}
}
/**
* The fragment
*/
public class VocabTestFragment extends Fragment {
private ViewGroup mRoot;
public final String TAG = getClass().getSimpleName();
private VocabWord mWord;
public static VocabTestFragment newInstance(ParcelableWord w) {
VocabTestFragment frag = new VocabTestFragment();
Bundle args = new Bundle();
args.putParcelable("word", w);
frag.setArguments(args);
return frag;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.mRoot = (ViewGroup) inflater.inflate(R.layout.fragment_practice_vocab, container, false);
ItalianWord word = null;
ParcelableWord pw = getArguments().getParcelable("word");
pw.printIt();
word = (ItalianWord) pw.getWord();
TextView tv = (TextView) this.mRoot.findViewById(R.id.word);
if(word != null) {
tv.setText(word.getmId() + " is the id\t" + word.getmWord());
} else {
tv.setText("Word not provided");
}
return this.mRoot;
}
}
/**
* fragment_practice_vocab
*/
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#android:drawable/gallery_thumb"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/word"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="placeholder"
android:layout_weight="4" />
</LinearLayout>
/**
* practice_activity
*/
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textViewProgressBarPractice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/practice_progress_bar"
/>
<FrameLayout
android:id="#+id/practice_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textViewProgressBarPractice"
>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="end"
android:layout_alignParentBottom="true"
>
<Button
android:id="#+id/buttonCheckWordPractice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Check"
/>
<Button
android:id="#+id/buttonCorrectWordPractice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:visibility="gone"
android:text="Correct"
/>
<Button
android:id="#+id/buttonIncorrectWordPractice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:visibility="gone"
android:text="Incorrect"
/>
</LinearLayout>
</RelativeLayout>

Android App: MainActivity Can't Find ListView/Crashes on Landscape->Portrait Mode

I'm having two issues with my Android application. I'll start with the relevant code, which I'm 99% certain is locked within my MainActivity class:
package com.simplerssreader;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
public class MainActivity extends FragmentActivity {
private ListView list;
private TextFragment text;
private RssFragment rss;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// Initializing AddNote fragment
if (getFragmentManager().findFragmentByTag("RSS") == null)
{
rss = new RssFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, rss, "RSS").commit();
}
}
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
{
if (getFragmentManager().findFragmentByTag("RSS") == null)
{
rss = new RssFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, rss, "RSS").commit();
}
if (getFragmentManager().findFragmentByTag("TEXT") == null)
{
text = new TextFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.text, text, "TEXT").commit();
}
}
//View view = getLayoutInflater().inflate(R.layout.fragment_layout, null);
list = (ListView) this.findViewById(R.id.listView);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id)
{
System.out.println("YES!");
/*RssAdapter adapter = (RssAdapter) parent.getAdapter();
RssItem item = (RssItem) adapter.getItem(position);
TextFragment fragment = new TextFragment();
fragment.setLink(item.getLink());
FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction xact = fragMgr.beginTransaction();
xact.replace(R.id.text, fragment, "TEXT");*/
}
});
if (savedInstanceState != null) {
text = (TextFragment) getSupportFragmentManager().findFragmentByTag("TEXT");
rss = (RssFragment) getSupportFragmentManager().findFragmentByTag("RSS");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("fragment_added", true);
}
}
(Note that I'm not concerned with the code within the onItemSelected at the moment; I'll deal with that later, when I actually have working code.)
So my first problem is with this line:
list = (ListView) this.findViewById(R.id.listView);
What I'm hoping to attain here is the ListView found in the current display (in portrait or landscape mode, the list view will be displayed). I also attempted another method in the commented out line above that, but it also failed. The error here is a NullPointerException.
My second issue is that whenever I go to portrait mode from landscape mode, the application crashes. I can go from portrait to landscape, and boot in either mode, but going back to portrait kills the application. I've made the proper checks for orientation in onCreate so I'm not sure of where I'm going wrong. The error here states that there's no TextView to find in the current view- but that should only be called when I'm in landscape mode, right?
Anyways, any help would be greatly appreciated!
Here are my layouts:
fragment_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#+id/listView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</ListView>
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
main.xml (portrait)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:id="#+id/fragment_container"
android:layout_height="fill_parent"
/>
text_view.xml
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
main.xml (landscape)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent"
android:baselineAligned="false">
<FrameLayout android:id="#+id/fragment_container" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground" />
<FrameLayout android:id="#+id/text" android:layout_weight="2"
android:layout_width="0px" android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground" />
</LinearLayout>
First, try moving the code where you get the list view to the fragment.
Also, in
if (savedInstanceState != null) {
text = (TextFragment) getSupportFragmentManager().findFragmentByTag("TEXT");
rss = (RssFragment) getSupportFragmentManager().findFragmentByTag("RSS");
}
you overwrite the text even if there was no TEXT fragment before, in case there's a savedInstance
Finally, you have duplicate ids:
<FrameLayout android:id="#+id/text" android:layout_weight="2"
android:layout_width="0px" android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground" />
and
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
Firstly, I don't see your ListView set to an Adapter in your activity. Here is just a simple example, where customtextview is a simple TextView and items a string array:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.customtextview, items);
listView.setAdapter(adapter);
Then, you have two id with "text" (R.layout.text_view and FrameLayout in R.layout.main landscape). If you use both in one of your Fragment, this will crash. Change one of them..
And, because you have the FrameLayout "text" only in landscape mode, you can do your onCreate method as below (check if this FrameLayout is present or not):
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// in both layout, you add this Fragment in the same FrameLayout
// check the savedInstanceState, if isn't null = orientation has changed
if (savedInstanceState == null)
rss = new RssFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, rss, "RSS").commit();
} else {
rss = (RssFragment) getSupportFragmentManager().findFragmentByTag("RSS");
}
/*
** check if FrameLayout text is null (true = landscape)
*/
if(findViewById(R.id.text) != null) {
// check the savedInstanceState
if (savedInstanceState == null) {
text = new TextFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.text, text, "TEXT").commit();
} else {
text = (TextFragment) getSupportFragmentManager().findFragmentByTag("TEXT");
}
}
/*
** else the id isn't exist (false = portrait) // do nothing
*/
}
Then, in your RSS Fragment, set your ListView:
private ListView list;
String[] items = new String[] {
"One",
"Two",
"Three",
"And so on.."
};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_layout, container, false);
list = (ListView) v.findViewById(R.id.listView);
ArrayAdapter<String> adapt = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, items);
list.setAdapter(adapt);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
System.out.println("YES!");
/* some stuff */
}
});
return v;
}
To save a fragment state on a activity, you can use setRetainInstance(true). There is a great post on it, and a tutorial. For more information about what happens with fragment and orientation changed, you can read this answer.
Let me know if this is helpful.
I searched a bit on the web, and I found these tutorials which might help you a lot:
great: Create Android Dynamic view with Fragments
great: User Interface Design: Working With Fragments
not bad: Fragment example tutorial using WebView
All works with WebView and they mostly use findFragmentById and not tag. Maybe it's the clue..
But you can add directly on the xml the appropriate fragments, as:
- Portrait Mode :
o layout 1 : listview (ex fragment RSS)
o layout 2 : fragment WebView
- Landscape Mode :
o layout 1 :
LinearLayout (id container) : listview (ex fragment RSS) + framelayout
And on your FragmentActivity, you host your list and check the orientation, like the following:
ListView list = (ListView) findViewById(...);
list.setAdapter(...);
LinearLayout container = (LinearLayout) findViewById(R.id.container);
if(container != null) {
// your framelayout is present so set your fragment WebView
// inside it with a fragment transaction and also
// use the item clicked to send info to this fragment
} else {
// call a new activity on item clicked to display the WebView
}
This should work..
I hope these added informations will help you to achieve that.

DialogFragment not floating, acts embeded or as another fragment

I have this app, that I created a custom dialog for. I must of goofed something up cause while the .show call on the dialog does indeed bring it up, it looks like a whole new fragment and it is not floating but instead replacing the ui with its contents. I did see in their help for DialogFragment:
http://hi-android.info/docs/reference/android/app/DialogFragment.html#Lifecycle
that one can embed a dialog as a regular fragment or not. Though I am not doing anything to do this so I cannot figure out why its acting like an embedded fragment and not floating. After thinking on it, is it the way I defined my XML definition? The dialogfragment example above didn't really give a definition for the xml layout, so maybe that is where my issue is? (Even added the gravity to the xml file, still no dice)
My xml definition for this Dialog is here:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:textSize="20sp"
android:text = "Location:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"/>
<Spinner
android:id="#+id/location_spinner"
android:layout_width = "450sp"
android:layout_height="wrap_content"/>
<!-- fill out the data on the package total cost etc -->
</LinearLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:id="#+id/location_dlg_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Okay"/>
<Button android:id="#+id/location_dlg_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"/>
<Button android:id="#+id/location_dlg_new"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Create new..."/>
</LinearLayout>
</LinearLayout>
Like I said displays just fine, the code for the fragment:
package com.viciousbytes.studiotab.subactivities.dialogfragments;
import ... ...
public class LocationPicker extends DialogFragment {
ArrayList<Location> mLocations;
public static LocationPicker newInstance()
{
LocationPicker loc = new LocationPicker();
return loc;
}
private void setLocations(ArrayList<Location> loc)
{
mLocations=loc;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Pick a style based on the num.
int style = DialogFragment.STYLE_NORMAL, theme = android.R.style.Theme;
setStyle(style, theme);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.location_dialog, container, false);
Spinner spinner = (Spinner)v.findViewById(R.id.location_spinner);
ArrayAdapter<Location> adapter = new ArrayAdapter<Location>(v.getContext(), android.R.layout.simple_spinner_item, mLocations);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
if(mLocations==null)
spinner.setPrompt("No Locations");
else
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new LocationSelectedListener());
// Watch for button clicks.
Button newBtn = (Button)v.findViewById(R.id.location_dlg_new);
newBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// When button is clicked, call up to owning activity.
//create new start that activity...
}
});
// Cancel do nothing dismissthis
Button cancelBtn = (Button)v.findViewById(R.id.location_dlg_cancel);
cancelBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// When button is clicked, call up to owning activity.
//create new start that activity...
}
});
// okay button means set listener with the selected location.
Button okBtn = (Button)v.findViewById(R.id.location_dlg_ok);
okBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// When button is clicked, call up to owning activity.
//create new start that activity...
}
});
return v;
}
}
It is called from a fragment itself? though does that matter? because I am calling a TimePIckerDialog and a DatePickerDialog and those work fine, but my calling code from my other fragment is:
void showLocationDialog() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("locpicker");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Create and show the dialog.
DialogFragment newFragment = LocationPicker.newInstance();
newFragment.show(ft, "locpicker");
}
Your constructors are wrong. Try to have just one static method newInstance to instantiate the fragment for all cases and use a Bundle to store the arguments that you want to use in the fragment. Refer to Basic Dialog section here and extend it to your case.

Categories

Resources