UPDATED ItemEntryFragment.java and ToDoActivity.java to include my latest attempt to get this thing to work, but it doesn't
I am in an android development class. our assignment is to make a simple todo list using two fragments. The first fragment is an EditText and the second is a listView.
when a user enters an item into the edittext box and hits enter, the string is added to the listview.
update 2 The application now successfully loads on my phone and the fragments look as expected. however when I press the enter key after inputting text in the EditText line, the setOnKeyListener is never fired. The code segments are the most current.
any suggestions/pointers would be appreciated.
Below are my xml files that I think are correct
main.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.todo.ToDoListFragment"
android:id="#+id/todolistFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment
android:name="com.todo.ItemEntryFragment"
android:id="#+id/textboxFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
_
list_view_fragment.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" >
<EditText
android:id="#+id/myEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/addItemContentDescription"
android:hint="#string/addItemHint" />
</LinearLayout>
_
edit_text_fragment.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" >
</LinearLayout>
and here are my .java files
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
public class ItemEntryFragment extends Fragment{
private ToDoListActivity activity;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.text_entry_box, container, false);
final EditText myEditText = (EditText)view.findViewById(R.id.myEditText);
myEditText.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN)
if((keyCode == KeyEvent.KEYCODE_DPAD_CENTER) || (keyCode == KeyEvent.KEYCODE_ENTER)) {
String newItem = myEditText.getText().toString();
activity.addItem(newItem);
myEditText.setText("");
return true;
}
return false;
}
});
return view;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.activity = (ToDoListActivity)activity;
}
}
_
public class ToDoListFragment extends ListFragment {
//this class is empty because the ListFragment auto adds the ListView
}
and here is my main java file
import java.util.ArrayList;
import android.app.Activity;
import android.app.FragmentManager;
import android.os.Bundle;
import android.widget.ArrayAdapter;
public class ToDoListActivity extends Activity {
private ArrayAdapter<String> aa;
private ArrayList<String> todoItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//inflate view
setContentView(R.layout.activity_to_do_list);
//get references to fragments
FragmentManager fm = getFragmentManager();
ToDoListFragment todoListFragment = (ToDoListFragment) fm.findFragmentById(R.id.todolistFragment);
todoItems = new ArrayList<String>();
//create array adaptor to bind array to list view
aa = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, todoItems);
//bind array adapter to list view
todoListFragment.setListAdapter(aa);
}
public void addItem(String newItem){
todoItems.add(newItem);
aa.notifyDataSetChanged();
}
}
Maybe try to hook into onEditorAction and set the EditText properties as mentioned here
Related
I have created two activities MainActivity and EditorActivity. I want to take two strings from Editor Activity and display those strings in MainActivity's ListView, whenever the back button from EditorActivity is clicked.
My code shows only one item and every time a new List is getting created.
MainActivity.java
package com.example.android.writedown;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private FloatingActionButton addNoteFab;
private ArrayList<NoteItem> notes = new ArrayList<>();
NoteAdapter adapter;
private static final String SHARED_PREF = "pref";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addNoteFab = (FloatingActionButton) findViewById(R.id.add_note);
adapter = new NoteAdapter(this, notes);
addNoteFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, EditorActivity.class);
startActivity(intent);
}
});
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_PREF, MODE_PRIVATE);
String title = sharedPreferences.getString("title", null);
String desc = sharedPreferences.getString("note", null);
notes.add(new NoteItem(title, desc));
ListView list = (ListView) findViewById(R.id.list_view);
adapter.notifyDataSetChanged();
list.setAdapter(adapter);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/add_note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_margin="16dp" />
</RelativeLayout>
EditorActivity.java
package com.example.android.writedown;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.EditText;
import java.util.ArrayList;
public class EditorActivity extends AppCompatActivity {
private EditText edit_title;
private EditText edit_note;
private SharedPreferences sharedPreferences;
private static final String SHARED_PREF = "pref";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
edit_title = (EditText) findViewById(R.id.edit_title);
edit_note = (EditText) findViewById(R.id.edit_note);
sharedPreferences = getSharedPreferences(SHARED_PREF, MODE_PRIVATE);
}
#Override
public void onBackPressed() {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("title", edit_title.getText().toString());
editor.putString("note", edit_note.getText().toString());
editor.commit();
Intent intent = new Intent(EditorActivity.this, MainActivity.class);
startActivity(intent);
}
}
activity_editor.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".EditorActivity">
<EditText
android:id="#+id/edit_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/editor_title"/>
<EditText
android:id="#+id/edit_note"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="#string/editor_note"
android:gravity="start"/>
</LinearLayout>
Custom Data type - NoteItem.java
package com.example.android.writedown;
import android.widget.TextView;
public class NoteItem {
private String title, note;
private TextView titleView, descView;
public NoteItem(String mTitle, String mNote) {
title = mTitle;
note = mNote;
}
public String getNote() { return note; }
public String getTitle() { return title; }
}
Custom Adapter - NoteAdapter.java
package com.example.android.writedown;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.List;
public class NoteAdapter extends ArrayAdapter<NoteItem> {
public NoteAdapter(#NonNull Context context, #NonNull List<NoteItem> notes) {
super(context, 0, notes);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View listItemView = convertView;
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(R.layout.note_list_item, parent, false);
}
NoteItem currNote = getItem(position);
String title = currNote.getTitle();
String desc = currNote.getNote();
TextView note_title = (TextView) listItemView.findViewById(R.id.note_title);
TextView note_desc = (TextView) listItemView.findViewById(R.id.note_description);
if(title!=null) {
note_title.setText(title);
note_title.setVisibility(View.VISIBLE);
}
if(desc!=null) {
note_desc.setText(desc);
note_desc.setVisibility(View.VISIBLE);
}
return listItemView;
}
}
note_list_item.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/note_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:fontFamily="sans-serif"
android:visibility="invisible"/>
<TextView
android:id="#+id/note_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:visibility="invisible"/>
</LinearLayout>
You're getting the SharedPreference with your key and every time replacing the same key values title and note which, as expected, would keep on overwriting the existing values instead of creating a list as per your requirement.
If you just need to save the data in one Activity and show it in a different activity, you can simply save the data as a list in the local storage (or even a remote database, if you prefer) and then get that instance to keep adding new elements to the list.
You can use PaperDB which is an easy-to-use NoSQL-based library for saving data in local storage. Check the link for integration, and once integrated you can simply save a file simply as:
Paper.book().write("editor_list", <you_list_here>);
Create the list like:
ArrayList<NoteItem> noteList = new ArrayList<>();
And then get the list instance from the local file in the EditorActivity as:
ArrayList<NoteItem> noteList = Paper.book().read("editor_list", new ArrayList<>()); // this will give you empty list if there are no existing items.
Then just add your title and note as a separate object of model class NoteItem and add it to the list like:
noteList.add(<your_object_here>)
Then you can use the write function again to pass this updated list and save the changes in the local file. For showing the list in the ListView simply get the file again as a list and pass the list to the adapter.
This should get it done what you're expecting!
I noticed in your MainActivity everything is written in onCreate method. If you understand the lifecycle of activity, onCreate calls only one time per launch of activity, I suggest to for another method like this
How to manage startActivityForResult on Android
and you don't require anything extra, just need to change the Intent calling with startActivityForResult and get in MainActivity in onActivityResult
I am trying to create a sort of a transparent tutorial which appears only
the first time. This is the fragment i have created. How do I add this on top of an existing layout
here's the code for the fragment
import android.app.Fragment;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import in.webblue.nuclity.Activity.Logs.SaveLog;
import in.webblue.nuclity.R;
import static android.content.Context.MODE_PRIVATE;
/**
* Created by Akshay on 15-06-2017.
*/
public class TutorialFragment extends Fragment {
private String Class_Name = "TutorialFragment";
private boolean ranBefore;
View topLevelLayout1;
View topLevelLayout2;
View myView;
String methodName = "onCreateView";
public static TutorialFragment newInstance() {
TutorialFragment f = new TutorialFragment();
return f;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = inflater.inflate(R.layout.tutorial_layout, container,
false);
topLevelLayout1=myView.findViewById(R.id.tutorial1);
topLevelLayout2=myView.findViewById(R.id.tutorial2);
if (!isFirstTime()) {
topLevelLayout1.setVisibility(View.INVISIBLE);
topLevelLayout2.setVisibility(View.INVISIBLE);
}
return myView;
}
private boolean isFirstTime()
{
try {
SharedPreferences preferences =
this.getActivity().getSharedPreferences("RanBefore", MODE_PRIVATE);
boolean ranBefore = preferences.getBoolean("RanBefore", false);
if (!ranBefore) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("RanBefore", true);
editor.commit();
topLevelLayout1.setVisibility(View.VISIBLE);
topLevelLayout2.setVisibility(View.INVISIBLE);
topLevelLayout1.setOnTouchListener(new
View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
topLevelLayout1.setVisibility(View.INVISIBLE);
topLevelLayout2.setVisibility(View.VISIBLE);
return false;
}
});
topLevelLayout2.setOnTouchListener(new
View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
topLevelLayout2.setVisibility(View.INVISIBLE);
return false;
}
});
}
}
catch (Exception e){
Log.e(getClass().getName(),"Method Name :"+methodName+ " "+ e.getStackTrace().toString());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
SaveLog.saveLog(getContext(),Class_Name,methodName,e.toString());
}
}
return ranBefore;
}
}
I need to add this on top of an existing layout
I think FrameLayout is the way to go here.
The secret of FrameLayout is how it layouts its children. Although normally designed to contain one item, it will happily stack up other element on top of each other. Thus FrameLayout is essentially a way to manipulate the Z-order of views on the screen
Here a thread about what a FrameLayout can do:
what does FrameLayout do?
So your Layout would look something like this:
<FrameLayout>
<Fragment/>
<LinearLayout>
// here is your normal layout
</LinearLayout>
</>
You could do it the following way.
This is your activity on top of which you need to add the fragment.
<?xml version="1.0" encoding="utf-8"?>
<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"
android:orientation="vertical">
<LinearLayout
android:id="#+id/example_fragment_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
//YOUR LAYOUT
</LinearLayout>
<LinearLayout
android:id="#+id/example_fragment_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="EndFragment">
/*THE FRAGMENT YOU WANT TO SHOW. THE LOGIC TO SHOW THIS FRAGMENT
ONLY ONCE WILL HAVE TO BE IN THE ACTIVITY ON TOP OF WHICH YOU ARE
SHOWING THIS FRAGMENT*/
<fragment
android:id="#+id/example_fragment"
android:name="com.example.ExampleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</RelativeLayout>
Now what you should do is show this fragment only once. The onClick method to hide this fragment is as follows:
public void EndFragment(View view) {
example_fragment_parent.setVisibility(View.GONE);
}
You need to find this fragment in the onCreate() of your activity like below:
LinearLayout example_fragment_parent =
(LinearLayout)findViewById(R.id.example_fragment_parent);
I have a function1 in FragA, and a function2 in FragB
What I want is : when FragA use function1, it should notify FragB to use functionB
So what is the easiest and good way to do it ?
Thanks
1. Using an EventBus
Use an EventBus to send event to the other fragment. You can try Otto or EventBus
2. Using FragmentManager and public method (I don't like these)
As #Alexander suggested, you can get reference to the other fragment and call its method
3. Using Broadcasts
You can use a LocalBroadcast and attach a receiver in both fragments to call the method when they receive a broadcast.
following is the example for your question, well it's quite crude in code but will give you an idea about how you can implement your requirement.
your activity should look like this FragmentTestOneActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import test.spinner.one.FragmentA;
import test.spinner.one.FragmentB;
public class FragmentTestOneActivity extends AppCompatActivity implements FragmentA.MyEventMaker{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_test_one);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
#Override
public void sendData(String text) {
Log.d("FragmentTestOneActivity", "Text: "+text);
FragmentB.setData(text);
}
}
and below is the layout for the above activity activity_fragment_test_one.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#cf5f5b"
android:orientation="horizontal"
android:padding="10dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="some.fragment.one.FragmentTestOneActivity"
tools:showIn="#layout/activity_fragment_test_one">
<fragment
android:id="#+id/fragment_one"
android:name="test.spinner.one.FragmentA"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:layout_weight="0.5"
tools:layout="#layout/fragment_" />
<fragment
android:id="#+id/fragment_two"
android:name="test.spinner.one.FragmentB"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:layout_weight="0.5"
tools:layout="#layout/fragment_b" />
</LinearLayout>
FragmentA.java
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
/**
* A simple {#link Fragment} subclass.
*/
public class FragmentA extends Fragment {
private MyEventMaker myEventMaker;
private Button button;
public FragmentA() {
// Required empty public constructor
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
myEventMaker = (MyEventMaker)context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_, container, false);
button = (Button) view.findViewById(R.id.FragmentA_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myEventMaker.sendData("something");
}
});
return view;
}
public interface MyEventMaker{
void sendData(String text);
}
}
fragment_a.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:gravity="center"
android:background="#b1a2f3"
tools:context="test.spinner.one.FragmentA">
<Button
android:id="#+id/FragmentA_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button" />
</LinearLayout>
FragmentB
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* A simple {#link Fragment} subclass.
*/
public class FragmentB extends Fragment {
private static TextView textView;
public FragmentB() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view =inflater.inflate(R.layout.fragment_b, container, false);
textView = (TextView)view.findViewById(R.id.FragmentB_textView);
return view;
}
public static void setData(String text){
Log.d("FragmentB","Text: "+ text);
textView.setText(""+text);
}
}
fragment_b.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:background="#efabca"
android:gravity="center"
tools:context="test.spinner.one.FragmentB">
<TextView
android:id="#+id/FragmentB_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
</LinearLayout>
From func1 find your B fragment using FragmentManager.findFragmentByTag (or byId) then call your function on that fragment.
Or you can use a 3rd party even bus such as Otto
I have an Activity that lays out ListFragments side by side (as many as a user wants) in a HorizontalScrollView upon choosing an option in the ActionBar.
Each ListFragment item contains TextViews and a Button. A SimpleAdapter populates data for each item in every ListFragment.
The issue I am facing now is that the buttons in each list item do not respond to clicks. The layout can be summarized as follows: Button inside a ListFragment inside a FragmentActivity, going from the innermost child element to the parent at the root view.
I have spent many hours on this problem and I am unable to arrive at a solution to make the buttons respond to clicks. Some of the approaches I have used include obtaining the button's view and attaching onClickListeners, 2) implementing the OnClickListener interface for the ListFragment. I am also aware of the onInterceptTouchEvent method for a ViewGroup class, however my lack of experience with Android prevents me from arriving at a solution. Any guidance or direction towards solving this problem would be most appreciated.
Here is the code for the ListFragment:
package com.example.androidlistfragmenttest;
import java.util.ArrayList;
import java.util.HashMap;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.SimpleAdapter;
public class MyFragment extends ListFragment {
private ArrayList<HashMap<String,String>> arraylist;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_layout, container, false);
Button button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener(){
//THIS DOES NOT PRINT IN LOGCAT. BUTTON DOES NOT RESPOND TO CLICKS.
#Override
public void onClick(View arg0) {
Log.v("GODZILLA","ATOMIC BREATH");
}
});
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
arraylist = dataGenerator();
SimpleAdapter adapter = new SimpleAdapter(getActivity().getApplicationContext(), arraylist, R.layout.fragment_layout,new String[]{"KEY"},new int[]{R.id.text_id});
setListAdapter(adapter);
}
/*
* Method to populate an adapter's data list.
*/
public ArrayList<HashMap<String,String>> dataGenerator(){
HashMap<String,String> hashMap1 = new HashMap<String,String>();
hashMap1.put("KEY", "A");
HashMap<String,String> hashMap2 = new HashMap<String,String>();
hashMap2.put("KEY", "B");
HashMap<String,String> hashMap3 = new HashMap<String,String>();
hashMap3.put("KEY", "C");
HashMap<String,String> hashMap4 = new HashMap<String,String>();
hashMap4.put("KEY", "D");
HashMap<String,String> hashMap5 = new HashMap<String,String>();
hashMap5.put("KEY", "E");
ArrayList<HashMap<String,String>> arraylist = new ArrayList<HashMap<String,String>>();
arraylist.add(hashMap1);
arraylist.add(hashMap2);
arraylist.add(hashMap3);
arraylist.add(hashMap4);
arraylist.add(hashMap5);
return arraylist;
}
} //End of MyFragment
And this is the code for the Activity containing the Fragment(s):
package com.example.androidlistfragmenttest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.NavUtils;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends FragmentActivity {
private Stack<String> tagStack;
private Integer last_tag_number;
public MainActivity(){
last_tag_number = new Integer("0");
tagStack = new Stack<String>();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.add_fragment:
addColumn();
return true;
case R.id.remove_column:
removeColumn();
return true;
case android.R.id.home:
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
/*
* This method adds a fragment to the screen
*/
public void addColumn(){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment fragment = new MyFragment();
fragmentTransaction.add(R.id.fragment_activity, fragment,tagGenerator());
fragmentTransaction.commit();
}
/*
* This method removes a fragment from the screen
*/
public void removeColumn(){
if(tagStack.size() != 0){
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tagStack.pop());
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.remove(fragment);
fragmentTransaction.commit();
}
}
/*
* This function generates tags for each fragment that is displayed on the screen
* The tags pose as unique identifiers for each fragment
*/
public String tagGenerator(){
Integer tag_number;
if(last_tag_number.intValue() == 0){
tag_number = last_tag_number;
int temp = last_tag_number.intValue();
temp+=1;
last_tag_number = Integer.valueOf(temp);
}
else{
tag_number = new Integer(last_tag_number.intValue());
int temp = last_tag_number.intValue();
temp+=1;
last_tag_number = Integer.valueOf(temp);
}
String tag = tag_number.toString();
tagStack.push(tag);
return tag;
}
} //End of MainActivity
As well as the layouts for the FragmentActivity:
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="#+id/fragment_activity"
android:layout_width="fill_parent"
android:layout_height = "fill_parent"
android:orientation = "horizontal"
android:gravity="center"
>
</LinearLayout>
</HorizontalScrollView>
And the ListFragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1"
android:layout_margin="5dp"
android:descendantFocusability="blocksDescendants" >
<ListView android:id="#id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:layout_gravity="center" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/label"
android:layout_gravity="start"
/>
<TextView
android:id="#+id/text_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="end"
/>
</LinearLayout>
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal" >
<Button
android:id="#+id/button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="#string/button"
android:layout_margin="2dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
/>
</LinearLayout>
</LinearLayout>
The problem is that the ListItem is consuming the click and it is not getting passed to the button below.
You need to set the list items to inactive and handle the clicks yourself. In your custom Adapter add the following methods to disable the items (They override methods from BaseAdapter):
#Override
public boolean areAllItemsEnabled() {
return false;
}
#Override
public boolean isEnabled(int position) {
return false;
}
Edit: Here is a related question that may offer a better solution, it depends on your design.
I have an activity which displays two fragments:
When activity is created, it displays Fragment1.
When the user presses the button on Fragment1, it displays Fragment2, adding to backstack.
Fragments are straightforward. Fragment1 contains CheckBox and EditText. Fragment2 contains simple TextView. Also I call setRetainInstance(true) in fragment's onCreate(...) method.
Problem: Fragment1 loses its state if Fragment2 is displayed and device is rotated twice. However, everything works as expected if device is rotate only once.
Steps to reproduce:
Launch application.
Check CheckBox and type some text into EditText
Press Button to launch Fragment2
Rotate device
Rotate device once again
Press Back button on your device (or ESC on Emulator) to return back to Fragment1
Fragment1 lost its state (checkbox is unchecked and EditText is empty).
However, if you return back to Fragment1 after step#4 - Fragment1 keeps its state as expected.
Where is the problem? All code is below, including layouts.
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent" />
fragment1.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" >
<CheckBox
android:id="#+id/checkBox1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox" />
<EditText
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</EditText>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Fragment2" />
</LinearLayout>
fragment2.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="Fragment #2" />
</LinearLayout>
FragmentTestActivity.java:
package fragmenttest.example.com;
import android.app.Activity;
import android.app.FragmentManager;
import android.os.Bundle;
public class FragmentTestActivity extends Activity implements FragmentListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag(Fragment1.TAG) == null) {
fm.beginTransaction().replace(R.id.placeholder, new Fragment1(), Fragment1.TAG).commit();
}
}
#Override
public void onButtonClick() {
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag(Fragment2.TAG) == null) {
fm.beginTransaction().replace(R.id.placeholder, new Fragment2(), Fragment2.TAG).addToBackStack(Fragment2.TAG).commit();
}
}
}
Fragment1.java:
package fragmenttest.example.com;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
public class Fragment1 extends Fragment {
public static final String TAG = Fragment1.class.getName();
private FragmentListener mListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment1, container, false);
Button button = (Button) root.findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mListener.onButtonClick();
}
});
return root;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mListener = (FragmentListener) activity;
}
}
Fragment2.java:
package fragmenttest.example.com;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment2 extends Fragment {
public static final String TAG = Fragment2.class.getName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment2, container, false);
return root;
}
}
FragmentListener.java:
package fragmenttest.example.com;
public interface FragmentListener {
public void onButtonClick();
}
It may be because onCreate isn't called when restoring the fragment.
See:http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)