I'm more googling to find how can i pass simple view as an object to fragment, but i can't.
for example in MainActivity i have simple view as :
TextView text = (TextView) findviewById(R.id.tv_text);
now i want to pass that to fragment. this below code is my attach Fragment on MainActivity
MainActivity :
public void attachFragment() {
fts = getActivity().getFragmentManager().beginTransaction();
mFragment = new FragmentMarketDetail();
fts.replace(R.id.cardsLine, mFragment, "FragmentMarketDetail");
fts.commit();
}
and this is my Fragment:
public class FragmentMarketDetail extends Fragment implements ObservableScrollViewCallbacks {
public static final String SCROLLVIEW_STATE = "scrollviewState";
private ObservableScrollView scrollViewTest;
private Context context;
private int scrollY;
public static FragmentMarketDetail newInstance() {
FragmentMarketDetail fragmentFirst = new FragmentMarketDetail();
return fragmentFirst;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_online_categories, container, false);
scrollViewTest = (ObservableScrollView) view.findViewById(R.id.scrollViewTest);
scrollViewTest.setScrollViewCallbacks(this);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getActivity().getBaseContext();
}
}
It wouldn't be good practise to pass a view that way. If you want to access the view in your activity from within your fragment class, use getActivity() to access the activity to which your fragment is attached, and from there you find your TextView.
TextView text = (TextView) getActivity().findViewById(R.id.tv_text);
How about adding a set function in your custom fragment
e.g.
public void setTextView(TextView tv){
this.tv = tv
}
and then calling it after
mFragment = new FragmentMarketDetail();
mFragment.setTextView(textView)
Find fragment by tag and invoke a function on it:
mFragment = (FragmentMarketDetail ) getActivity().getFragmentManager().findFragmentByTag(FragmentMarketDetail .class.getSimpleName());
mFragment.passTextView(textView);
Of course fragment must be added to backstack.
Related
I want to move some data from my Mainactivity to a Fragment...which is inside a tab fragment (which handles a SectionPagerAdapter)....which is inside a fragment in Mainactivity2.
I feel its too complicated and cant get it done.
GameEndedActivity (See wrong and correct variable...these are to be transferred)
public class GameEndedActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_ended);
int correct = getIntent().getIntExtra("correct", 0);
int wrong = getIntent().getIntExtra("wrong", 0);
}
}
TabFragment
public class TabFragment extends Fragment {
private int tabsCount;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_tab, container, false);
if(this.getContext() instanceof ChallengeOverviewActivity){
tabsCount = 2;
} else {
tabsCount = 3;
}
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this.getContext(), getFragmentManager(), tabsCount);
ViewPager viewPager = view.findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = view.findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
return view;
}
}
ResultFragment (Transfer data here - wrong and correct variables)
public class ResultDetailsFragment extends Fragment {
private TextView tvWrong, tvCorrect;
private AnswerListener answerListener;
public interface AnswerListener {
public void correct(int i);
public void wrong(int i);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_result_details, container, false);
tvCorrect = view.findViewById(R.id.tvCorrect);
tvWrong = view.findViewById(R.id.tvWrong);
return view;
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
if (context != null) {
answerListener = (AnswerListener) context;
}
}
}
One way to do this is the add arguments to the fragment when you create an instance of it. In your activity when you create the fragment you want to attach you add some arguments to it. These arguments can then be accessed from the fragments onCreate method.
Just do this same thing again when you are in your fragment and create your second one.
Check this answer out which explains more in detail how to do it: https://stackoverflow.com/a/17436739/964887
MainActivity on startup add a fragment layout to Relativeview, then i send a data to fragment to add it to ExpandablelistView but my app shows me error that couldn't recognize ExpandablelistView.
MainActivity:
public class MainActivity extends AppCompatActivity implements FragmentAddCatergory.onClickButtonListener {
private FragmentManager manager;
private FragmentTransaction transactionShowList;
private FragmentTransaction transactionAddCatergory;
private FragmentAddCatergory addCatergory;
private FragmentShowCategory showCategory;
private boolean addcategory;
private TextView txtAddCategory;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = getFragmentManager();
transactionShowList = manager.beginTransaction();
showCategory = new FragmentShowCategory();
addCatergory=new FragmentAddCatergory();
transactionShowList.add(R.id.Fragment_container, showCategory);
transactionShowList.commit();
addcategory=false;
txtAddCategory = (TextView) findViewById(R.id.txtaddcategory);
txtAddCategory.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ChangeFragment();
}
});
}
public void ChangeFragment(){
transactionAddCatergory=manager.beginTransaction();
if (addcategory){
transactionAddCatergory.replace(R.id.Fragment_container,addCatergory);
txtAddCategory.setText("Do you want to see your List?Show me!");
addcategory=false;
}else{
transactionAddCatergory.replace(R.id.Fragment_container,showCategory);
txtAddCategory.setText("Do you want to add a Category?Create One");
addcategory=true;
}
transactionAddCatergory.commit();
}
#Override
public void ClickButton(String group, String child) {
FragmentShowCategory a=new FragmentShowCategory();
a.showExpand(this,group,child);
}}
in last above code i make object from first fragment and send a data and in below code is code of first fragment
public class FragmentShowCategory extends Fragment {
private View view;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
view = inflater.inflate(R.layout.activity_expandable_list_view, container, false);
return view;
}
public void showExpand(Context context, String g, String c) {
Toast.makeText(context, g + " is " + c, Toast.LENGTH_LONG).show();
HashMap<String, List<String>> carsDetails = DataProvider.getInfo(g, c);
List<String> carsBrands = new ArrayList<String>(carsDetails.keySet());
ItemClass adapter = new ItemClass(context, carsDetails, carsBrands);
ExpandableListView list = (ExpandableListView) view.findViewById(R.id.expandList);
list.setAdapter(adapter);
}}
but when i ran my app, i get error that i don't know why in line of:
ExpandableListView list = (ExpandableListView) view.findViewById(R.id.expandList);
i'd appreciate to help me.
Your fragment's view hierarchy is not inflated automatically just because you created an instance of your fragment, as you do in ClickButton. The onCreateView() method that has to be called first in order to inflate your views is part of the fragment's lifecycle. You should let Android instantiate your fragment, and acquire it's instance through the FragmentManager.
This tutorial explains basics about fragments very well.
i have a fragment inside a activity, this fragment contains a viewpager, this is the code:
public class RepliesContainerFragment extends Fragment {
#InjectView(R.id.viewPager)
ViewPager pager;
private PagerAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ReplyActivity replyActivity = (ReplyActivity) getActivity();
List<Replie> replies = getArguments().getParcelableArrayList("replies");
adapter = new PagerAdapter(replyActivity.getSupportFragmentManager(), replies);
setActionBar();
}
private void setActionBar() {
getActivity().getActionBar().setDisplayHomeAsUpEnabled(false);
getActivity().getActionBar().setIcon(getResources().getDrawable(R.drawable.ic_back));
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
getActivity().getActionBar().setTitle("Respuestas");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.work_containter_replies, container, false);
ButterKnife.inject(this, view);
pager.setAdapter(adapter);
return view;
}
}
Inside the adapter i had instantiate some fragments like this:
public class ReplyFragment extends Fragment {
#InjectView(R.id.tvQuestion)
TextView tvQuestion;
#InjectView(R.id.frameContainter)
FrameLayout replyContainer;
private ReplyView replyView;
private String question;
private String currentReplie;
private int replieType;
private int questionId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
replieType = getArguments().getInt("replyType");
question = getArguments().getString("question");
questionId = getArguments().getInt("questionId");
currentReplie = getArguments().getString("currentReplie");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.work_reply_fragment, container, false);
ButterKnife.inject(this, view);
initQuestionText();
return view;
}
private void persistReply() {
ReplyActivity replyActivity = (ReplyActivity) getActivity();
if (replyActivity != null) {
//DO SOMETHING
//Notify to adapter from here
}
}
}
}
As you can see, i want to notify to my RepliesContainerFragment and his inside adapter that some event happens and do an action..
How can i do it this?
With broadcastreceivers, with callbacks(Interfaces)..?I am not sure.
The very simple solution for this is to pass a listener instance from your parent fragment to a child fragment. You have to create a listener interface, create an instance of it in your parent fragment, and pass that instance to all your children fragments.
By the way there is a topic regarding this problem in the official tutorial.
Hope this helps.
I think it is easier:
private void persistReply() {
ReplyActivity replyActivity = (ReplyActivity) getActivity();
if (replyActivity != null) {
//DO SOMETHING
RepliesContainerFragment frag = ((RepliesContainerFragment)this.getParentFragment());
frag.getAdapter().notifyDataSetChanged();
}
}
}
and make getter setter for adapter
What I need to achieve
A screen displaying a ListView, which can be replaced by an error screen in case of problems (missing connection, server unavailable and the like).
I need to be able to switch (programmatically) back and forth between these two screens.
Requirements
The main screen must be a Fragment.
This is because my application is composed of several sections, each one accessible from the navigation drawer.
What I have done so far
The main fragment class is named AllQueuesFragment: its XML layout consists of a FrameLayout, which I use in combination with the FragmentManager to switch between ErrorFragment (containing the error message) and QueuesViewFragment (containing the ListView).
public class AllQueuesFragment extends Fragment
{
public AllQueuesFragment()
{
super();
}
#Override
public void onStart()
{
super.onStart();
// Show the right fragment based on connectivity status
checkConnection();
}
public void checkConnection()
{
final NetworkManager netManager = NetworkManager.getInstance(this.getActivity());
if (netManager.isConnected())
showQueues();
else
showNoConnection();
}
public void showNoConnection()
{
ErrorFragment fragNoConnection = new ErrorFragment();
displayFragment(fragNoConnection);
fragNoConnection.setTitle(R.string.text_no_connection);
fragNoConnection.setIcon(R.drawable.thatfeel);
fragNoConnection.setLoaderVisibility(false);
}
public void showQueues()
{
QueuesViewFragment fragQueuesView = new QueuesViewFragment();
displayFragment(fragQueuesView);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_allqueues, container, false);
return rootView;
}
// Displays a new fragment
public void displayFragment(Fragment fragment)
{
if (fragment != null)
{
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
}
}
}
The error screen is the following:
public class ErrorFragment extends Fragment
{
private TextView textTitle;
public ErrorFragment()
{
super();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_error, container, false);
// Get the widgets
textTitle = (TextView)rootView.findViewById( R.id.fragment_error_text );
return rootView;
}
// Set methods
public void setTitle(int id) { textTitle.setText(id); }
}
The problem
The setTitle() method gets called before the layout is ready, and as a result, a NullPointerException is thrown.
class AllQueuesFragment
{
....
public void displayFragment(Fragment fragment)
{
if (fragment != null)
{
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
}
}
public void showNoConnection()
{
ErrorFragment fragNoConnection = new ErrorFragment();
displayFragment(fragNoConnection);
// PROBLEM HERE: Before calling setTitle(), I must be sure that ErrorFragment's
// layout is inflated!
fragNoConnection.setTitle(R.string.text_no_connection);
}
....
}
class ErrorFragment
{
....
public void setTitle(String value) { textTitle.setText(value); }
....
}
I can't call setTitle() directly from ErrorFragment::onCreateView(), because I don't know beforehand which message I need to show.
How can I ensure that fragNoConnection has completed its layouting?
Is there a better way to achieve my goal?
Unsatisfying workaround
The only workaround I can think of is to use a buffer to defer the actual call:
class ErrorFragment
{
// This string will hold the title until the layout is inflated
private String titleBuffer;
private TextView textTitle = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_error, container, false);
// Get the widgets
textTitle = (TextView)rootView.findViewById( R.id.fragment_error_text );
// Do the actual set
setTitle(titleBuffer);
return rootView;
}
....
public void setTitle(String value)
{
titleBuffer = value;
// If the layout is not inflated, defer the actual set
if (textTitle != null)
textTitle.setText(titleBuffer);
}
....
}
but I don't like this solution very much (the code above is simplified; ErrorFragment has more properties).
Advices?
Thanks in advance
This is exactly the type of thing arguments are supposed to be used for:
public void showNoConnection() {
ErrorFragment fragNoConnection = new ErrorFragment();
Bundle args = new Bundle();
//you can also use putInt here if you'd rather pass a string resource id, along with anything else you can stick into a Bundle
args.putString("title", "some title");
fragNoConnection.setArguments(args);
displayFragment(fragNoConnection);
}
Then in ErrorFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_error, container, false);
TextView textTitle = (TextView)rootView.findViewById( R.id.fragment_error_text );
//now retrieve the argument...
textTitle.setText(getArguments().getString("title"));
return rootView;
}
The Fragment will even remember it's arguments after an orientation change.
If you feel like being pedantic, you can create a static factory method within ErrorFragment that takes the title as an argument and then creates the Fragment and adds the argument, that way you can achieve proper encapsulation :)
You need to have a callback method in your ErrorFragment and when the view is inflated you then call the method in your callback interface in the onViewCreated and set the title.
sample:
in ErroFragment
public class ErroFragment extends Fragment
{
static interface ErrorDone{
public void doneInflating();
}
private TextView textTitle;
private ErrorDone ed;
public ErroFragment()
{
super();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_error, container, false);
// Get the widgets
textTitle = (TextView)rootView.findViewById( R.id.fragment_error_text );
return rootView;
}
// Set methods
public void setTitle(int id) { textTitle.setText(id); }
public void setInterFace(ErrorDone er){ this.ed = er; }
}
Then you implement the interface in your AllQueuesFragment
public class AllQueuesFragment extends Fragment implements ErroFragment.ErrorDone
It will generate method doneInflating
and you need to set the interface:
public void showNoConnection()
{
ErrorFragment fragNoConnection = new ErrorFragment();
displayFragment(fragNoConnection);
fragNoConnection.setInterFace(this);
}
And in the generated method(doneInflating) of the AllQueuesFragment you then set the title in there:
public void doneInflating(){
fragNoConnection.setTitle(R.string.text_no_connection);
fragNoConnection.setIcon(R.drawable.thatfeel);
fragNoConnection.setLoaderVisibility(false);
}
If you want to be sure that the FragmentTransaction is commited and effective, you can use the executePendingTransactions method:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
fragmentManager.executePendingTransactions();
But, the right way to do it is to send the title value to the Fragment when instantiating it. This is the default pattern when you create a Fragment from your IDE (eclipse or Android Studio)
I am trying to show a FragmentDialog ( created and shown as a dialog NOT added as content in a view hierarchy) where there is a ViewPager whose content is given by a FragmentPagerAdapter (provides Fragments consisting of an image).
The code works perfect when showing ViewPager + FragmentPagerAdapter from a FragmentActivity, but get the following exception when doing it from a FragmentDialog:
"IllegalArgumentException: No view found for id 0x7f040077 for fragment SimpleFragment..."
Here is my code:
A SherlockFragmentActivity with a button to create and show the dialog.
public class BorrameActivity extends SherlockFragmentActivity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.one_act);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
showTheDialog();
}});
}
private void showTheDialog(){
AchGalleryDialog newFragment = AchGalleryDialog.newInstance(achs);
newFragment.show(getSupportFragmentManager(), "dialog");
}
The FragmentDialog:
public class AchGalleryDialog extends DialogFragment{
public AchGalleryDialog(){
}
public static AchGalleryDialog newInstance(){
AchGalleryDialog f = new AchGalleryDialog();
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_user_result, container);
getDialog().setTitle("Hola tronco");
//content to show in the fragments
int[] images = new int[]{R.drawable.d1, R.drawable.d2, R.drawable.d3};
ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
MyFragmentAdapter adapter = new MyFragmentAdapter(getFragmentManager(),images);
pager.setAdapter(adapter);
return view;
}
}
This is the very simple MyFragmentPagerAdapter,
I put only the getItem() method, and nullPointer checks:
#Override
public Fragment getItem(int position) {
return MySimpleFragment.newInstance(images[position]);
}
And finally SimpleFragment:
public class SimpleFragment extends Fragment{
int id;
public static SimpleAchFragment newInstance(int imgId){
SimpleFragment f = new SimpleFragment();
Bundle args = new Bundle();
args.putLong(ID_BUNDLE, imgId);
f.setArguments(args);
return f;
}
public SimpleAchFragment(){
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.id = getArguments() != null ? getArguments().getInt(ID_BUNDLE) : 0;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.simple_fragment, container, false);
FragmentActivity mAct = getActivity();
ImageView img = (ImageView) v.findViewById(R.id.image);
img.setImageDrawable(mAct.getResources().getDrawable(id));
return v;
}
}
More info, if the content passed to the adapter ( an int array with 3 ints) has length zero, then the adapter doesn't try to create any Fragment so dialogs appears correctly but empty (as expected).
The Exception is thrown at SimpleFragment.onCreateView() at the time of inflating.
The id referenced in the exception (as not found) correspond to ViewPager 's id, with is properly defined in R.layout.simple_fragment.
I have try also to build the Dialog with an AlertDialog.builder and also directly with Dialog() contructor, but get the same behaviour.
Try this:
In class AchGalleryDialog
MyFragmentAdapter adapter = new MyFragmentAdapter(getChildFragmentManager(),images);
instead of
MyFragmentAdapter adapter = new MyFragmentAdapter(getFragmentManager(),images);
Because of this:
http://developer.android.com/about/versions/android-4.2.html#NestedFragments
Hope this will help!