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


71

我有一个受支持的片段活动,它将加载diff片段。该片段带有一些textViewid = "score"我想得到它的句柄,但是findViewById对于score的textView返回为null。为什么这样?


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    
    }

}

您的textview放在哪里?它是片段布局吗?如果是,则必须调用scoreBoardTextView =(TextView)findViewById(R.id.score); 在片段的onCreateView中。事情是这样的:stackoverflow.com/questions/24156139/...
卓然

在片段中。在片段中
user93796 2014年

您无法从单独的lYout中获得视图。
Rod_Algonquin 2014年

@Rod_Algonquin没让你
user93796 2014年

4
您是否要从活动中更新Fragment的TextView?您最好在Fragment本身中执行此操作。
Yaroslav Mytkalyk 2014年

Answers:


67

注意:

直接在片段外部访问片段的视图不是一个好主意。您应该使用片段回调接口来处理此类情况并避免错误。以下方法可行,但不建议这样做,因为这不是一个好习惯。


如果您要访问TextViewFragment其父里面Activity,那么你应该定义你里面的方法Fragment类是这样的:

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);
    }


}

现在,您可以Activity像这样在内部使用它:

myFragment.setTextViewText("foo");

这是myFragment类型MyFragment

如果要访问整体,TextView则可以在内部定义如下方法MyFragment.java

public TextView getTextView1(){
    return mTextView;
}

通过此操作,您可以访问TextView自身。

希望这可以帮助。:)


2
这看起来是一个很好的答案,但是我认为覆盖show的方法是onCreateView()and not getView()
matiash

这是使用view.findViewById()的正确方法
-Android Noob

您不应该这样做...活动为何直接访问Fragment的视图???您为什么不只是将这些视图移动到活动的布局?这样使用片段有什么好处?
kupsef 2014年

@kupsef不要问我问OP。我只是在告诉它如何完成。我不会直接访问该视图。那就是为什么我也演示了第一种方法。
SMR 2014年

1
您可以以一种可以告诉您特定视图是否可见的方式实现该片段。它更干净。该片段负责该视图,而Activity使用该片段提供的接口来获取有关视图的信息。没有直接访问。
kupsef

21

可以通过以下方式进行:

像这样在Fragment中保留膨胀视图的引用:

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;
}

}

在Activity中创建一个函数,如下所示:

 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();
}

其目的是保留当前片段的参考。每当您想切换片段时,都可以调用上面的函数,如下所示(来自片段):

activity.switchContent( new MyFragment_2());

现在,您具有当前的片段参考。因此,您可以像这样直接在Activity中访问Fragment的视图:this.fragment.view


不错的技巧,我会尝试的...!
2014年

父级活动永远不要直接操纵片段的视图。您应该在执行修改的片段中编写一个函数。直接访问片段的视图实际上使片段无用。这样就失去了封装,您最好将这些视图添加到Activity的布局中。
kupsef 2014年

@kupsef显然,我们必须通过方法来访问它们,我只是在这里进行了了解。
2014年

11

您无需引用Fragment视图即可在Activity中获取其组件。因为您可以直接在父Activity中访问Fragment的布局组件。

简单地说,您可以由此访问任何组件

findViewById(R.id.child_of_fragment_layout);  

4
一个警告(至少对我而言)是正确的,片段视图可能尚未准备好。当我将该代码移至我的活动中时,它起作用了onStart()
Amr Mostafa

5

为了访问TextView或Button或片段中的任何内容,您需要执行以下操作:

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);
}

在MainActivity或要从Fragment访问TextView的任何其他对象中完成此操作后,应确保以其他可能会抛出nullPointer的方式在OnCreate()方法中设置该片段。因此,您要更改TextView的活动应如下所示:

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");

        }
    });
}

希望这可以帮助 :)


4

您可以使用Fragment类的getView方法进行访问。

例如,您在MyFragment中有一个ID为“ text_view”的TextView
在您的活动中,制作一个您的片段:

MyFragment myFragment = new MyFragment();

当您需要一个孩子时,只需调用getView,然后找到您的childView。

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

注意:如果您想要片段的根视图,那么myFragment.getView();就足够了。


我对您的回答有疑问,如果R.id.something是根视图,那么getView()就足够了
cutiko 2016年

@cutiko是的,getView方法返回片段布局的根
Saman Sattari

3

只是放入片段而不是进行活动:

@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;
}

我需要在加载片段的父级活动中使用“ scoreBoardTextView”活动的句柄。该怎么办?
user93796 2014年

1
把手是什么意思?您是否需要更改textview(文本,背景...),或者在活动中需要textview中的文本?
Zoran 2014年

好像您对获得答案不感兴趣?
Zoran 2014年

@Zoran Hey,是的,我需要能够从textview中的按钮onClick片段中获取字符串
Amogh Jahagirdar


2

如果您的TextView放置在Fragment内,那么您将无法访问Fragment Parent Activity内的TextView ,则可以设置Fragment与Activity互通的接口,并在单击TextView或您想要发生的任何其他事情时发送数据


1

您无法访问FragmentParent中的element Activity,但是您可以通过Fragment以下方式将值传递给您。

在您的onNavigationDrawerItemSelected方法中MyActivity执行以下操作

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();
}

然后在MyFragment课堂上创建一个方法,newInstance如下所示

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;
}

和中MyFragmentonCreateView()方法

@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;
}

仅此而已,希望对您有所帮助。如果没有,请告诉我。


0

分数textView在片段的布局中,不在MyActivity的布局中,即R.layout.activity_home。因此,在为相应的布局文件充气后,您可以在该片段中找到得分textview。


我需要在加载片段的父级活动中使用“ scoreBoardTextView”活动的句柄。该怎么办?
user93796 2014年

0

返回,null因为TextView是的元素,而Fragment不是Activity

请注意,使用的想法Fragment是将模块封装在中Fragment,这意味着Activity不能直接访问其属性。考虑将逻辑移到在TextView内部获得引用的位置Fragment


0

只需在片段中将TextView声明为公共,即可通过片段的onCreateView()中的findViewById()对其进行初始化。现在,通过使用在活动中添加的“片段对象”,您可以访问TextView。


0

您需要从片段视图中调用方法findViewById。

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); 
}

这种方式对我有用。


0

我建议您将textview作为活动布局的一部分。或者,您可以将textview作为单独的片段。在这里看看我的问题。它与您的相似,但方向相反。这是我在项目中使用的简化代码版本。解释与代码一致。

活动课

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");

}

}

片段类:

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
}

}

从活动到片段的交流是直接的。这是因为活动包含片段。保留片段对象,并通过设置器和获取器或其中的公共字段访问其属性。但是从片段到活动的通信需要一个接口。


0

为什么不直接从FragmentPagerAdapter访问它,

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

这是完整的示例:

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);
    }
}

0

如果视图在屏幕上已经膨胀(例如可见),那么您可以照常在活动中使用findViewById(R.id.yourTextView),它将把句柄返回到文本视图;如果未找到该视图,则返回null。


0

我只使用方法从父级活动访问片段视图,因为我们创建了一个新的片段类对象来插入片段。所以我喜欢这样。

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
    }
}

MainActivity

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

val webView = browserFragment.getWebView()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.