Hello fellow developers!
i'll keep this as simple and short as I can,
I have a fragment, and in my onCreateView I am sometimes giving it different layouts depend on my status.
is there any way of knowing on which layout I am?
code below:
my onCreateView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view;
if (programState) {
view = inflater.inflate(R.layout.fragment_home_program_on, container, false);
} else {
view = inflater.inflate(R.layout.fragment_home, container, false);
}
findViews(view);
setupViews();
return view;
}
basically, my "findViews" method gets that View, and I was wondering if there's a way to know which layout i am on with a switch statement for example or something like that.. like this :
private void findViews(View mainView) {
switch(mainView) {
case R.layout.fragment_home:
//do work
break;
case R.layout.fragment_home_program_on:
//do work
break;
}
}
I am trying to do something like that with no success.. all i get is errors and such, is there a way to do that?
thanks a lot in advance
is there any way of knowing on which layout I am?
Sure. Check programState. You are already doing that to determine which layout to load, so use that to determine which layout you loaded.
I was wondering if there's a way to know which layout i am
Use if (programState), the same way you did in onCreateView().
Beyond that, a widget has no idea what layout resource it came from. So, somewhere, you need to track that information yourself, and you seem to be doing so already in programState.
try mainView.getId() in switch. I think that's what you need
Change your method to something like this:
private void findViews(View mainView) {
int viewId = mainView.getId();
switch(viewId) {
case R.id.firstViewId:
//do work
break;
case R.id.secondViewId:
//do work
break;
}
}
If you have various Views and you need to differentiate them - try adding tags to them.
1 - If you are going to have more then one tag type - create keys for them.
And use mainView.setTag(TAG_TYPE_ID_1, 10011) (many tags for a view) rather than mainView.setTag(10011) (only one tag for a view).
In this case TAG_TYPE_ID_1 may be your constant field. It must be initialized with id of some Resource. For example public static final int TAG_TYPE_ID_1 = R.layout.my_frame_layout;
Also consider placing int viewId = (int) mainView.getTag() into try/catch because you can get ClassCastException if you will put there a String for example but will try to get int.
But for this example we assume you don't need lots of tags and you know that you have only int as a tag.
2 - Set tag into the view in onCreateview() method in your fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view;
if (programState) {
view = inflater.inflate(R.layout.fragment_home_program_on, container, false);
view.setTag(1011);
} else {
view = inflater.inflate(R.layout.fragment_home, container, false);
view.setTag(1012);
}
findViews(view);
setupViews();
return view;
}
3 - Then read the tag value in your view and decide what to do
private void findViews(View mainView) {
if(mainView.getTag() == null)
return;
switch((int) mainView.getTag()) {
case 1011:
//do work
break;
case 1012:
//do work
break;
}
}
NOTE: don't forget that here switch((int) mainView.getTag()) you can get ClassCastException or NullPointerException if tag will be different type or null
Also int codes like 1011, 1012 etc. is better to store as a constant fields
Related
I have a problem, whenever i try to add an eventhandler to a button i get a null reference exception, i am trying to create a popup window with a DialogFragment, where inside it im calling the view PopUpWindow wich will show up on screen, but when i try to access the buttons by id and to assign them eventhandlers for example:
Button btnCopyText = dp.view.FindViewById<Button>(Resource.Id.btnCopyText);
btnCopyText.Click += BtnCopyText_Click;
then i get a null reference exception, can anyone help me, below is the necessary code.
class dialog_Popup:DialogFragment
{
public View view;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView(inflater, container, savedInstanceState);
view = inflater.Inflate(Resource.Layout.PopupWindow, container, false);
return view;
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
Dialog.Window.RequestFeature(WindowFeatures.NoTitle);
base.OnActivityCreated(savedInstanceState);
}
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
//some code
}
public string itemclicked;
dialog_Popup dp;
private void Lv_ItemLongClick(object sender, AdapterView.ItemLongClickEventArgs e)
{
//View popUpView = LayoutInflater.Inflate(Resource.Layout.PopupWindow,
//null); // inflating popup layout
Button height = FindViewById<Button>(Resource.Id.btnCopyText);
//Then: change the width of the button
FragmentTransaction transaction = FragmentManager.BeginTransaction();
dp = new dialog_Popup();
dp.Show(transaction,"Popup");
itemclicked = lv.GetItemAtPosition(e.Position).ToString();
Button btnCopyText = dp.view.FindViewById<Button>(Resource.Id.btnCopyText);
btnCopyText.Click += BtnCopyText_Click;
Button btnSaveCurrentAya = dp.view.FindViewById<Button>(Resource.Id.btnSaveCurrentAya);
btnSaveCurrentAya.Click += BtnSaveCurrentAya_Click;
Button btnsavingsAya = dp.view.FindViewById<Button>(Resource.Id.savingsAya);
btnsavingsAya.Click += BtnsavingsAya_Click;*
Button btnShareFB = dp.view.FindViewById<Button>(Resource.Id.fbShare);
btnShareFB.Click += BtnShareFB_Click;
}
}
There are several reasons why a NullReferenceException can occur with FindViewById:
The layout does not contain the id -> check that the correct layout and id is inflated/ referenced
The type like Button is incorrect
In your case, check that dp and dp.view is not null.
One thing to mention here is, that it is not the best implementation to reference the control of a fragment in you main view. A fragment is something that should be able to life on her own. So I see two ways of implementing your desired behavior:
1) The fragment gets an event and you listen to that. This means your main view will contain the logic to save something.
2) The logic moves into the fragment.
Since, i am new to android, i am trying to learn fragments and how they work.I tried to make a length converter app which basically converts meter to centimeters.Simple, right?
Now I have two portions of the activity,one being the two edittexts which are the part of the activity layout, while the other one being the fragment.
This fragment basically contains keypad, in short, Numbers and operators displayed on it. Like a normal calci would have.
Now i read about the fragment life cycle and how it is supposed to work.
So The first thing that i did was to put everything in onCreateView method.
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
getRootView=inflater.inflate(R.layout.calci_keyboard,container,false);
GridLayout gridLayout=(GridLayout) getRootView.findViewById(R.id.calciKeyboardGrid);
for(int i=0;i<gridLayout.getChildCount();i++){
b=(Button)gridLayout.getChildAt(i);
b.setBackground(getResources().getDrawable(R.drawable.button_dark_gradient));
b.setOnClickListener(this);
}
return getRootView;
}
The thing is that, click events work but edittext settext doesn't seem to work. Edittexts are behaving weirdly.
Now, to remove that i thought i am accessing the Activity UI's , so i should do this inside onActivityCreated function ,So, i tried this too.
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
getRootView=inflater.inflate(R.layout.calci_keyboard,container,false);
return getRootView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
#SuppressLint("InflateParams") View getView=(GridLayout) LayoutInflater.from(getActivity()).inflate(R.layout.calci_keyboard,null,false);
GridLayout gridLayout=(GridLayout) getView.findViewById(R.id.calciKeyboardGrid); // i Logged this obj and it was there
for(int i=0;i<gridLayout.getChildCount();i++){
b=(Button)gridLayout.getChildAt(i);
b.setBackground(getResources().getDrawable(R.drawable.button_dark_gradient));
b.setOnClickListener(this);
}
}
When i do things this way i don't seem to get my clicks working?
How am i supposed to do this problem? Can't find any solution.
Go easy on me,Thanks :)
Below one shows my onClick event:.
public void onClick(View view) {
View focussedChild=getActivity().getCurrentFocus();
switch (view.getId()){
case R.id.calciKeyboardNine:{
if (focussedChild instanceof EditText) {
firstPart=new StringBuilder("");
secondPart=new StringBuilder("");
EditText editText=(EditText)focussedChild;
if(focussedChild.getId()==R.id.lengthConverterFirst){
if(!TextUtils.isEmpty(firstPart.toString()))
firstPart.replace(0,firstPart.length()-1,editText.getText().toString()+"9");
firstPart.append("9");
editText.setText(firstPart.toString());
editText.setSelection(editText.length());
int a=Integer.parseInt(firstPart.toString());
a=a*100;
editText=getActivity().findViewById(R.id.lengthConverterSecond);//second edit text
editText.setText(Integer.toString(a));
editText.setSelection(editText.length());
}else if(focussedChild.getId()==R.id.lengthConverterSecond){
if(!TextUtils.isEmpty(secondPart.toString()))
secondPart.replace(0,secondPart.length()-1,editText.getText().toString()+"9");
secondPart.append("9");
editText.setText(secondPart.toString());
editText.setSelection(editText.length());
double a=Integer.parseInt(firstPart.toString());
a=a/100;
editText=getActivity().findViewById(R.id.lengthConverterFirst);//first edit text
editText.setText(Double.toString(a));
editText.setSelection(editText.length());
}
}
}
}
}
Now, to remove that i thought i am accessing the Activity UI's , so i should do this inside onActivityCreated function ,So, i tried this too - it didn't work because onActivityCreated() is method of fragment not activity.
try this - just make your edittexts static in activity and then you can access them in fragment by the activity's name like MainActivity.editText(). hope this helps
This is more of a design question and how one would go about designing applications. I have been having fun with fragments, but one thing that doesn't make sense to me something like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 2);
Button btnOne = (Button) getView().findViewById(R.id.one);
btnOne.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
String currentText = getScreen().getText().toString();
currentText += "1";
getScreen().setText(currentText);
}
});
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.standard_calculator, container, false);
return view;
}
/** Return the screen TextView object for manipulation
* #return screen
*/
public TextView getScreen() {
return screen;
}
Screen title are private variables in the class and this isn't the whole class, but just the part that I need to help my question. There are going to be at least 15 or so buttons that manipulate the screen and it doesn't feel like good practice to and put them all in the onCreate method, I was wondering whether it would be better design to have them in another class that let the methods in the fragment be more specific to the life-cycle of the fragment, although one can say that the buttons are used by the fragment and therefore should be part of the class. Perhaps an "initialising" method is needed.
I was hoping someone might be able to direct me to some design patterns or logical way of thinking about application design, it is quite different.
Many thanks.
Putting them in the XML is less versatile than doing it in code. If you don't want to have XXX anonymous methods, you can make your own Fragment/Class implement View.onClickListener and implement the onClick method:
#Override
public void onClick(final View v) {
if ( v.getId() == R.id.btn_logout ){
// Do One Thing
} else if ( v.getId() == R.id.btn_about) {
// Do Something Else
} else if ( v.getId() == R.id.btn_shutdown) {
// Or Maybe do this :)
}
}
Then in your onViewCreated just assign each button with "this"
final someBtn = (Button) view.findViewById(R.id.btn_logout);
someBtn.setOnClickListener(this);
That can be cleaner looking than a bunch of anonymous methods and you know you have your click listeners in one place.
You don't have to initialize them all in the onCreate() method. In fact, you don't have to initialize them in java code at all. You could simply define them in xml and define an "onClick" property in your xml. The method that you set in "onClick" will be called for that button. It's one way to make your Activities cleaner.
I have a some fragment in my PageViewer.
In the main fragment, I would like to show a component ( TextView or imageView) if there is no connection.
In the code below, I can reach my textview, but I cannot get them disapperead.
public class MainFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.main, container, false);
// RelativeLayout mainLayout = (RelativeLayout)findViewById(R.layout.main);
TextView TxtIsNotConnected = (TextView) layout.findViewById(R.id.isNotConnected);
TextView TxtIsConnected = (TextView) layout.findViewById(R.id.isConnected);
// String text = TxtIsNotConnected.getText().toString(); // This is a test which works, return the text o my textview.
boolean isConnected = ConnectivityUtils.isConnected(getActivity()); // This Works fine
if (!isConnected) TxtIsNotConnected.setVisibility(View.VISIBLE); // NOT WORKING
else TxtIsConnected.setVisibility(View.VISIBLE); // NOT WORKING
return inflater.inflate(R.layout.main, container, false);
}
How should I do???
To make your TextView visible
yourTextView.setVisibility(View.VISIBLE);
To make Invisible
yourTextView.setVisibility(View.GONE);
From your code it seems that you have to keep one view visible and another invisible. So, please try this
if (!isConnected) {
TxtIsNotConnected.setVisibility(View.VISIBLE);
TxtIsConnected.setVisibility(View.GONE);
} else {
TxtIsConnected.setVisibility(View.VISIBLE);
TxtIsNotConnected.setVisibility(View.GONE);
}
Hope it helps...
Edit :
Well, your code is correct about visibility but you have made a silly mistake that's why it seems that your code is not working. Look at the first line and last line of your onCreateView method. You have inflated your R.layout.main in View object called "layout". You have set your actions within that layout. Finally you have returned a new instance of that view. So, your previous codes became useless. So, your return statement will be...
return layout ;
It should fix the problem.
My users should be able to change (using preferences) how the interface looks like (visually enabling and disabling certain layouts dynamically) in my app.
I'm working with the v4 ViewPager (PagerTabStrip to be exact) and am trying to change this in the onResume() method, right after the user closes the "settings menu" to return to the app.
I can change variables this way, but cannot seem to change anything layoutwise (I used to work with TabHosts, where this worked perfectly). If I call this method in the onCreateView() method, everything works fine, but I don't want my users to force close the app before any changes can be visible.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = null;
vContainer = container; // global variable
switch (mCurrentPage) {
case 1:
v = inflater.inflate(R.layout.lifepoints_layout,
container, false);
// irrelevant code
InputStyleType = (LinearLayout) v
.findViewById(R.id.llInputEditText);
InputStyleButtons = (TableLayout) v
.findViewById(R.id.tlInputButtons);
InitializePreferences(); // <- this method
break;
case 2:
// irrelevant code
break;
default:
break;
}
return v;
}
This works perfectly, as it should. However, when the code gets called via the onResume(), the program crashes!
#Override
public void onResume() {
super.onResume();
if (isPaused)
InitializePreferences();
isPaused = false;
}
This is the method itself:
public void InitializePreferences() {
SharedPreferences getPreferences = PreferenceManager
.getDefaultSharedPreferences(getActivity().getBaseContext());
prefInput = getPreferences.getBoolean("pref_input", true);
prefFb = getPreferences.getBoolean("pref_fb", false);
if (prefInput) {
InputStyleType.setVisibility(View.GONE);
InputStyleButtons.setVisibility(View.VISIBLE);
} else {
InputStyleButtons.setVisibility(View.GONE);
InputStyleType.setVisibility(View.VISIBLE);
}
}
I've tried a lot, but nothing seems to work. It seems I cannot change anything layoutwise unless it's directly called from the onCreateView, which doesn't seem right.
EDIT 1
I've analysed my method completely, it gets called correctly and I've tested with some variables. Everything works fine until I'm trying to change something that is visible to the user (toasts work perfectly fine).
EDIT 3
Deleted Edit 2 and this is where my code stands at the moment. It's still not working, and it's actually a bit of a mess. I do think the answer isn't far off.
public void InitializePreferences() {
SharedPreferences getPreferences = PreferenceManager
.getDefaultSharedPreferences(getActivity().getBaseContext());
prefInput = getPreferences.getBoolean("pref_input", true);
prefFb = getPreferences.getBoolean("pref_fb", false);
if (isPaused) {
getActivity().getWindow().getDecorView().invalidate();
LayoutInflater inflater = (LayoutInflater) getActivity()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.lifepoints_layout, vContainer,
false);
InputStyleType = (LinearLayout) v.findViewById(R.id.llInputEditText);
InputStyleButtons = (TableLayout) v
.findViewById(R.id.tlInputButtons);
InputStyleType.invalidate();
InputStyleButtons.invalidate();
}
if (prefInput) {
InputStyleType.setVisibility(View.GONE);
InputStyleButtons.setVisibility(View.VISIBLE);
} else {
InputStyleButtons.setVisibility(View.GONE);
InputStyleType.setVisibility(View.VISIBLE);
}
}
I think you need to invalidate your views. Try adding InputStyleType.invalidate() and InputStyleButtons.invalidate() to the InitializePreferences method. You might need to also invalidate the view parent(s) that contain InputStyleType and InputStyleButtons.
EDIT: Try this in the onResume() callback:
LayoutInflater inflater = getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.lifepoints_layout,
container_2, false);
To make this work create a global ViewGroup variable and set it's value to the value of container in the onCreateView callback.
container_2 = container;