问题
I'm trying out the new class in android Honeycomb preview, and I've got a small issue. I am making a baseball scoring app, and I want the buttons on the left (Action Menu) to switch the "Action Pane" on the right, which I've set up as a fragment.
I'd like the buttons' onClickListener() to call a Fragment Transaction to swap it out. So far it works, EXCEPT that when the app loads, it creates the default fragment, but when I hit a button, instead of REPLACING the default fragment, it creates a whole new one next to it.
I've looked for hours, and I can't see what I'm doing wrong...
Keep in mind I'm new to java/android/programming, so I might be missing something that's painfully obvious.
hc_test.java (main activity)
package com.pte.hc_test;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class hc_test extends Activity {
/** Called when the activity is first created. */
/* declare class-level variables */
// private LinearLayout touchPad;
// private TextView touchCoordText;
private Button pitchButton;
private Button hitButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pitchButton = (Button)findViewById(R.id.actionButton1);
hitButton = (Button)findViewById(R.id.actionButton2);
pitchButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
swapFragment(actionType.PITCH_ACTION);
}
});
hitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
swapFragment(actionType.HIT_ACTION);
}
});
}
private void swapFragment(int myType){
Fragment f = new actionFragment(myType);
// Execute a transaction, replacing any existing
// fragment with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.actionFragment, f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- this is the parent layout of the whole screen -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#2F2F4F"
>
<!-- SCOREBOARD MASTER LAYOUT -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<!-- team name placeholders -->
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:padding="5dp"
>
<TextView style="@style/inningLabel"
android:text="TEAM"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:text="@string/visitor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:text="@string/home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
<!-- end team names -->
<!-- Inning table -->
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:fadingEdge="vertical">
<TableLayout
android:id = "@+id/innings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
>
<!-- inning label row -->
<!-- get these done with code?? -->
<TableRow android:layout_height="wrap_content">
<TextView style="@style/inningLabel"
android:id="@+id/inn1_label"
android:text="1"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/inn2_label"
android:text="2"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/inn3_label"
android:text="3"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/inn4_label"
android:text="4"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/inn5_label"
android:text="5"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/inn6_label"
android:text="6"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/inn7_label"
android:text="7"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/inn8_label"
android:text="8"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/inn9_label"
android:text="9"
android:layout_height="wrap_content"
/>
</TableRow>
<!-- end inning labels -->
<!-- top inning row -->
<TableRow android:layout_height="wrap_content">
<TextView style="@style/inningValue"
android:id="@+id/top1_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/top2_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/top3_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/top4_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/top5_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/top6_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/top7_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/top8_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/top9_label"
android:text="0"
android:layout_height="wrap_content"
/>
</TableRow>
<!-- end top inning row -->
<!-- bottom inning row -->
<TableRow android:layout_height="wrap_content">
<TextView style="@style/inningValue"
android:id="@+id/bot1_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/bot2_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/bot3_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/bot4_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/bot5_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/bot6_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/bot7_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/bot8_label"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/bot9_label"
android:text="0"
android:layout_height="wrap_content"
/>
</TableRow>
<!-- end bottom inning row -->
</TableLayout>
</HorizontalScrollView>
<!-- end inning table -->
<!-- Runs, Hits, Errors Count -->
<TableLayout
android:id = "@+id/RHE"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:padding="5dp">
<TableRow android:layout_height="wrap_content">
<TextView style="@style/inningLabel"
android:id="@+id/runLabel"
android:text="R"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/hitLabel"
android:text="H"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningLabel"
android:id="@+id/errorLabel"
android:text="E"
android:layout_height="wrap_content"
/>
</TableRow>
<TableRow android:layout_height="wrap_content">
<TextView style="@style/inningValue"
android:id="@+id/visitorRuns"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/visitorHits"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/visitorErrors"
android:text="0"
android:layout_height="wrap_content"
/>
</TableRow>
<TableRow android:layout_height="wrap_content">
<TextView style="@style/inningValue"
android:id="@+id/homeRuns"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/homeHits"
android:text="0"
android:layout_height="wrap_content"
/>
<TextView style="@style/inningValue"
android:id="@+id/homeErrors"
android:text="0"
android:layout_height="wrap_content"
/>
</TableRow>
</TableLayout>
</LinearLayout>
<!-- END OF SCOREBOARD LAYOUT -->
<!-- MAIN ACTIVITY SECTION -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!-- ACTION MENU BEGIN -->
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<Button
android:id="@+id/actionButton1"
android:text="ActionButton1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/actionButton2"
android:text="ActionButton2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/actionButton3"
android:text="ActionButton3"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/actionButton4"
android:text="ActionButton4"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/actionButton5"
android:text="ActionButton5"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
<!-- ACTION MENU END -->
<!-- ACTION FRAME BEGIN -->
<fragment class="com.pte.hc_test.actionFragment"
android:id="@+id/actionFragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<!-- ACTION FRAME END -->
</LinearLayout>
<!-- MAIN ACTIVITY SECTION END -->
<!-- LIVE STATS FRAME BEGIN -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!-- left live stat pane -->
<LinearLayout
android:id="@+id/left_stat_pane"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
>
<TextView style="@style/statHeader"
android:id="@+id/left_playerName"
android:text="{PITCHER NAME}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView style="@style/statText"
android:id="@+id/left_stat1"
android:text="Stat1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView style="@style/statText"
android:id="@+id/left_stat2"
android:text="Stat2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView style="@style/statText"
android:id="@+id/left_stat3"
android:text="Stat3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
<!-- end left live stat pane -->
<!-- right live stat pane -->
<LinearLayout
android:id="@+id/right_stat_pane"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
>
<TextView style="@style/statHeader"
android:id="@+id/right_playerName"
android:text="{BATTER NAME}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView style="@style/statText"
android:id="@+id/right_stat1"
android:text="Stat1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView style="@style/statText"
android:id="@+id/right_stat2"
android:text="Stat2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView style="@style/statText"
android:id="@+id/right_stat3"
android:text="Stat3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
<!-- end right live stat pane -->
</LinearLayout>
</LinearLayout>
actionFragment.java
package com.pte.hc_test;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
public class actionFragment extends Fragment {
// class variables
int mActivityType;
// default (null) constructor
public actionFragment(){
Log.v("PTE", "null constructor");
}
public actionFragment(int n){
mActivityType = n;
Log.v("PTE", "explicit constructor (" + n + ")");
}
@Override
public void onCreate(Bundle saved){
super.onCreate(saved);
if (saved != null){
mActivityType = saved.getInt("Type");
}
Log.v("PTE", "FIRE: actionFragment.onCreate()");
}
@Override
public void onSaveInstanceState(Bundle toSave){
toSave.putInt("Type", mActivityType);
Log.v("PTE", "FIRE: actionFragment.onSaveInstanceState()");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
Log.v("PTE", "FIRE: actionFragment.onCreateView()");
Log.v("PTE", "with mActivityType == " + mActivityType);
try {
Log.v("PTE", "with onCreateView()'s container = " + container.toString());
} catch (Exception e) {
Log.v("PTE", "could not convert container to string. Must be null");
Log.v("PTE", e.toString());
}
Context c = getActivity().getApplicationContext();
LinearLayout actionPane = new LinearLayout(c);
switch (mActivityType) {
case actionType.PITCH_ACTION:
Log.v("PTE", "FIRE: actionFragment.pitchPane()");
// instantiate all the required views
// parent container
TextView topLabel = new TextView(c);
TableLayout strikeZone = new TableLayout(c);
ImageView image = new ImageView(c);
// set properties for each view
actionPane.setOrientation(LinearLayout.VERTICAL);
topLabel.setText("top Label Text");
// create the strike zone table
for(int i=1; i<6; i++){
TableRow tr = new TableRow(c);
for(int j=1; j<6; j++){
TextView tv = new TextView(c);
tv.setText("C" + j + ":R" + i);
tv.setPadding(3, 3, 3, 3);
tr.addView(tv);
}
strikeZone.addView(tr);
}
image.setPadding(0, 60, 0, 30);
image.setImageResource(R.drawable.homeplate);
// add child views to parent
actionPane.addView(topLabel);
actionPane.addView(strikeZone);
actionPane.addView(image);
return actionPane;
case actionType.HIT_ACTION:
Log.v("PTE", "FIRE: actionFragment.hitPane()");
// simple layout with a text view for testing
TextView placeholder = new TextView(c);
placeholder.setText("This is a placeholder");
actionPane.addView(placeholder);
return actionPane;
default:
Log.v("PTE", "FIRE: actionFragment.defaultPane()");
// If I comment this TextView out, I achieve my intended behavior
TextView label = new TextView(c);
label.setText("This is the default pane");
actionPane.addView(label);
return actionPane;
}
}
}
回答1:
The placeholder text you were putting in the default for the switch statement was creating a view via your LinearLayout actionPane. A fragment was never added to the container. When you hit your buttons, the swapFragment method was called and a fragment added to the container next to the actionPane view.
If you delete the creation of the actionPane in the default you didn't see the issue as you noted. If you wanted to display some default view or text in a fragment for the initial launch of the app to be replaced by the fragments fired by the buttons, you can add a fragment to the container in the hc_test onCreate method. This will then be swapped out when you fire the buttons. I tested this and it works, may not be the best way and its 2 am now so please excuse me if I'm not writing clearly! Can send you or post the code if you like.
I'm curious if you found a tutorial to help you set up your fragments with the buttons? All I could find were listFragment examples and was struggling until I found your post.
Thanks,
回答2:
I've made a few changes to the code, and it works as I intended. For anyone who's interested, here's the relevant snippits from the working version. I didn't post the code for the individual fragment layouts, but it's really just the xml version of what I was doing in the code in the first draft. I'm liking the simplicity of the inflater object that onCreateView utilizes, it keeps the code to a minimum, and I can make the layout changes in XML without changing code.
actionFragment.java
package com.pte.StatCast;
// imports
public class actionFragment extends Fragment {
// class variables
int mActivityType;
// default (null) constructor
public actionFragment(){
}
public actionFragment(int n){
this.mActivityType = n;
}
@Override
public void onCreate(Bundle saved){
super.onCreate(saved);
if (saved != null){
mActivityType = saved.getInt("Type");
}
}
@Override
public void onSaveInstanceState(Bundle toSave){
toSave.putInt("Type", mActivityType);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
Context c = getActivity().getApplicationContext();
LinearLayout.LayoutParams p =
new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 1);
View actionPane = new View(c);
switch (mActivityType) {
case actionType.PITCH_ACTION:
// inflate XML resource to create pitch_frag view
actionPane = inflater.inflate(R.layout.pitch_frag, null);
actionPane.setLayoutParams(p);
// set up listener for touch events
ImageView strikeZoneImg = (ImageView)actionPane.findViewById(R.id.strikeZone);
strikeZoneImg.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent e) {
//DO STUFF
});
return actionPane;
case actionType.HIT_ACTION:
// inflate XML resource to create hit_frag view
actionPane = inflater.inflate(R.layout.hit_frag, null);
actionPane.setLayoutParams(p);
return actionPane;
default:
LinearLayout l = new LinearLayout(c);
l.setLayoutParams(p);
return l; // return a blank linear layout as the default action
}
}
}
StatCast.java
package com.pte.StatCast;
// imports
public class StatCast extends Activity {
/** Called when the activity is first created. */
// Declare stuff
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// database stuff here
/*
* Swap in the pitch fragment when activity first loads
*/
swapFragment(actionType.PITCH_ACTION);
}
private void swapFragment(int myType){
Fragment f = new actionFragment(myType);
// Execute a transaction, replacing any existing
// fragment with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.actionFragment, f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
Log.v("PTE", "COMPLETED: swapFragment");
}
}
I'm still not entirely sure why the first attempt didn't work, but this method seems to me a little cleaner, and it works so I'm not complaining. If you have thoughts or comments, I'm still all ears to learn about this stuff. Thanks!
来源:https://stackoverflow.com/questions/5054113/android-fragment-duplication