如何在片段的父活动中访问片段的子视图?

我有一个受支持的片段活动,它将加载不同的片段。片段有一些 textViewid = "score",我想得到它的句柄,但 findViewById为得分的 textView返回空。为什么?


TextView 放置在片段中

public class MyActivity extends  extends ActionBarActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks{


private TextView scoreBoardTextView = null;


protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
scoreBoardTextView = (TextView) findViewById(R.id.score); //this returns null
}


@Override
public void onNavigationDrawerItemSelected(int position) {
//set fragment
}


}
106236 次浏览

The score textView is in the layout of fragment, it's not in the layout of the MyActivity, i.e. R.layout.activity_home. So you could find the score textview in that fragment once you inflate the corresponding layout file.

Just put in fragment instead of putting in activity:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_new_work_order,
container, false);


TextView scoreBoardTextView = (TextView) rootView.findViewById(R.id.score);


return rootView;
}

It returns null cause the TextView is an element of the Fragment, not the Activity.

Please note that the idea of using Fragment is to encapsulate a module inside the Fragment, which means the Activity should not have direct access to it's properties. Consider moving your logic where you get the TextView reference inside the Fragment

Note:

Directly accessing fragment's views outside fragment is not a good idea. You should use fragment callback interfaces to handle such cases and avoid bugs. The following way works but it is not recommended as it is not a good practice.


If you want to access the TextView of Fragment inside its parent Activity then you should define a method inside your Fragment class like this:

public class MyFragment extends Fragment {


TextView mTextView;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_main, container, false);
mTextView = (TextView) view.findViewById(R.id.textView1);
return view;
}


public void setTextViewText(String value){
mTextView.setText(value);
}




}

Now you can use this inside your Activity like this:

myFragment.setTextViewText("foo");

here myFragment is of type MyFragment.

If you want to access the whole TextView then you can define a method like this inside MyFragment.java:

public TextView getTextView1(){
return mTextView;
}

By this you can access the TextView itself.

Hope this Helps. :)

It is possible with following way:

Keep reference of inflated view in the Fragment like this :

public class MyFragment extends SherlockFragment{


MainMenuActivity activity;
public View view;
public MyFragment(){
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {


if ( getActivity() instanceof MainMenuActivity){
activity = (MainMenuActivity) getActivity();
}


view = inflater.inflate(R.layout.aboutus, container, false);
return view;
}


}

Create a function in the Activity, like this:

 public class MainMenuActivity extends SherlockFragmentActivity {


SherlockFragment fragment = null;


public void switchContent(SherlockFragment fragment) {
this.fragment = fragment;
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.mainmenu, fragment)
.commit();


invalidateOptionsMenu();
}

Its purpose is to keep reference of current fragment. Whenever you wanna switch fragment, you call above function, like this (from fragment):

activity.switchContent( new MyFragment_2());

Now you've current fragment reference. So you can directly access Fragment's views in Activity like this: this.fragment.view

You can't access Fragment element in Parent Activity, But You can pass values to your Fragment by following way.

in your onNavigationDrawerItemSelected method of MyActivity do the following

int myScore = 100;
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager
.beginTransaction()
.replace(R.id.container,
MyFragment.newInstance(myScore)).commit();
}

And in MyFragment class create a method called newInstance like following

private static final String SCORE = "score";
public static MyFragment newInstance(int score) {
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putInt(SCORE, score);
fragment.setArguments(args);
return fragment;
}

And in MyFragment's onCreateView() method

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
TextView textView = (TextView) rootView
.findViewById(R.id.score);
textView.setText(Integer.toString(getArguments().getInt(
SCORE)));
return rootView;
}

That's All, I hope this will help you. If not please let me know.

Simply declare TextView as public in fragment, initialize it by findViewById() in fragment's onCreateView(). Now by using the Fragment Object which you added in activity you can access TextView.

You need to call method findViewById from your fragment view.

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
scoreBoardTextView = (TextView) mNavigationDrawerFragment.getView().findViewById(R.id.score);
}

This way works for me.

If your TextView placed inside Fragment that case you cannot access TextView inside your Fragment Parent Activity you can set the interface for intercommunication between Fragment and Activity and send Data when you click on TextView or anyother thing which you want to happend

I suggest you to make the textview part of your activity layout. Alternately you can have the textview as a separete fragment. Have a look at my question here. Its similar to yours but in reverse direction. Here's a stripped down version of code I used in my project. The explanation are along the code.

The Activity Class

public class MainActivity extends ActionBarActivity {
PlaceFragment fragment;
TextView fragmentsTextView;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}


@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Bundle bundle = new Bundle();
bundle.putString("score", "1000");
fragment = PlaceFragment.newInstance(bundle);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, fragment);
ft.addToBackStack(null);
ft.commit();
// method 1
// fragment is added some ways to access views
// get the reference of fragment's textview
if (fragment.getTextView() != null) {
fragmentsTextView = fragment.getTextView();
}
// method 2
// using static method dont use in production code
// PlaceFragment.textViewInFragment.setText("2000");


// method 3
// let the fragment handle update its own text this is the recommended
// way wait until fragment transaction is complete before calling
//fragment.updateText("2000");


}


}

The fragment class:

public class PlaceFragment extends Fragment {
public TextView textViewInFragment;// to access via object.field same to
// string.length


// public static TextView textViewInFragment;//to access via
// PlaceFragment.textView dont try this in production code
public PlaceFragment() {
}


public static PlaceFragment newInstance(Bundle bundle) {
PlaceFragment fragment = new PlaceFragment();
fragment.setArguments(bundle);
return fragment;
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.fragment_place, container, false);
textViewInFragment = (TextView) view
.findViewById(R.id.textViewInFragment);
return view;
}


@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
if (getArguments() != null) {
textViewInFragment.setText(getArguments().getString("score"));


}
}


public TextView getTextView() {
if (textViewInFragment != null) {
return textViewInFragment;// returns instance of inflated textview
}
return null;// return null and check null
}


public void updateText(String text) {
textViewInFragment.setText(text);// this is recommended way to alter
// view property of fragment in
// activity
}


}

Communication from activity to fragment is straight forward. This is because activity contains fragment. Keep the fragment object and access its property via setters and getters or the public fields inside it. But communication from fragment to activity requires an interface.

You can access with getView method of Fragment class.

For example You have a TextView in Your MyFragment with id of "text_view"
In Your Activity make a Fragment of Yours:

MyFragment myFragment = new MyFragment();

And when You need a child just call getView and then find Your childView.

View view = myFragment.getView();
if (view !=null) {
view.findViewById(R.id.text_view).setText("Child Accessed :D");
}

Note: if you want the root view of your fragment, then myFragment.getView(); is simply enough.

why you don't access it directly from your FragmentPagerAdapter,

SubAccountFragment subAccountFragment = (SubAccountFragment) mSectionsPagerAdapter.getItem(1);
subAccountFragment.requestConnectPressed(view);

and here is the full example:

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;


import java.util.Locale;




public class TabsActivity extends ActionBarActivity implements ActionBar.TabListener {


/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link FragmentPagerAdapter} derivative, which will keep every
* loaded fragment in memory. If this becomes too memory intensive, it
* may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;


/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);


// Set up the action bar.
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);


// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());


// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);


// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});


// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
ActionBar.Tab tab = actionBar.newTab();


View tabView = this.getLayoutInflater().inflate(R.layout.activity_tab, null);


ImageView icon = (ImageView) tabView.findViewById(R.id.tab_icon);
icon.setImageDrawable(getResources().getDrawable(mSectionsPagerAdapter.getPageIcon(i)));


TextView title = (TextView) tabView.findViewById(R.id.tab_title);
title.setText(mSectionsPagerAdapter.getPageTitle(i));


tab.setCustomView(tabView);


tab.setTabListener(this);


actionBar.addTab(tab);
}
}




@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_tabs, menu);
return true;
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();


//noinspection SimplifiableIfStatement
if (id == R.id.action_logout) {
finish();
gotoLogin();
return true;
}


return super.onOptionsItemSelected(item);
}


@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}


@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}


@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}


/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {


public ProfileFragment profileFragment;
public SubAccountFragment subAccountFragment;
public ChatFragment chatFragment;


public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
profileFragment = new ProfileFragment();
subAccountFragment = new SubAccountFragment();
chatFragment = new ChatFragment();
}


@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return profileFragment;
case 1:
return subAccountFragment;
case 2:
return chatFragment;
}
return null;
}


@Override
public int getCount() {
// Show 3 total pages.
return 3;
}


@Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}


public int getPageIcon(int position) {
switch (position) {
case 0:
return R.drawable.tab_icon_0;
case 1:
return R.drawable.tab_icon_1;
case 2:
return R.drawable.tab_icon_2;
}
return 0;
}
}




public void gotoLogin() {
Intent intent = new Intent(this, LoginActivity.class);
this.startActivity(intent);
}


public void requestConnectPressed(View view){
SubAccountFragment subAccountFragment = (SubAccountFragment) mSectionsPagerAdapter.getItem(1);
subAccountFragment.requestConnectPressed(view);
}
}

Only doing this:

((Your_Activity) this.getActivity()).YouyActivityElements;

If the view is already inflated (e.g. visible) on the screen then you can just use findViewById(R.id.yourTextView) within the activity as normal and it will return the handle to the text view or null if the view was not found.

You have no need of reference of Fragment view to get its components in Activity. As you can directly access layout components of a Fragment in parent Activity.

Simply you can access any component by this

findViewById(R.id.child_of_fragment_layout);

In order to access the TextView or Button or whatever in your fragment you need to do the following:

public class BlankFragment extends Fragment {
public View view;
public TextView textView;
public Button button;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view =inflater.inflate(R.layout.fragment_blank, container, false);
textView = (TextView)view.getRootView().findViewById(R.id.textView_fragment1);
return view;
}


public void changeTextOfFragment(String text){
textView.setText(text);
view.setBackgroundResource(R.color.colorPrimaryDark);
}

Once that is done in your MainActivity or any other where you want to access your TextView from your Fragment you should make sure to set up the fragment in your OnCreate() method other ways it will most likely throw nullPointer. So your activity where you want to change the TextView should look smth like this:

public class MainActivity extends AppCompatActivity {
private Button button1;
private FragmentManager fragmentManager;
private FragmentTransaction fragmentTransaction;
BlankFragment blankFragment = new BlankFragment();


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button)findViewById(R.id.button1);
changeFragment();


fragmentManager = getFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment1,blankFragment);
fragmentTransaction.commit();
}


private void changeFragment(){
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {


blankFragment.changeTextOfFragment("Enter here the text which you want to be displayed on your Updated Fragment");


}
});
}

Hope this helps :)

I just use methods to access fragment views from parent activity, because we create a new fragment class object to insert the fragment. So I do like this.

class BrowserFragment : Fragment(), Serializable {
private lateinit var webView: NestedScrollWebView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
webView = view.findViewById(R.id.web_view)
}
fun getWebView(): WebView {
return webView
}
}

In MainActivity

val browserFragment = BrowserFragment()
val fragmentTransaction = supportFragmentManager.beginTransaction()
fragmentTransaction.add(R.id.browser_fragment_placeholder, browserFragment)
fragmentTransaction.commit()


val webView = browserFragment.getWebView()