I already know that we have a configuration section in UrbanAirship site (Configuration -> In-App Messages) and read http://docs.urbanairship.com/platform/android.html#custom-style. But with this I can't change all the In-App layout.
In Sum:
How I can change the style for button (apply border, changing
background color just for the button, color to the text button ...)?
Base.Widget.UrbanAirship.InAppMessage.Banner.ActionButton
How I can hide the divider between the button and notification description?
Base.Widget.UrbanAirship.InAppMessage.Banner.Divider
Layout adjustments take a little bit more work but can be done. First you will need to create a custom InAppMessageFragment:
public class CustomInAppMessageFragment extends InAppMessageFragment {
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
if (getMessage() == null || getMessage().getAlert() == null) {
dismiss(false);
return null;
}
// Bind the in-app message to the layout. The fragment is attached to the content of the activity,
// so it has the full activity width and height to work with.
TextView view = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, container, false);
view.setText(getMessage().getAlert());
return view;
}
}
Then set the fragment factory on the in-app message manager after takeOff:
airship.getInAppMessageManager().setFragmentFactory(new InAppMessageFragmentFactory() {
#Override
public InAppMessageFragment createFragment(InAppMessage message) {
return new CustomInAppMessageFragment();
}
});
Take a look at the source to see how the in-app message fragment's view is normally created.
Related
How can I use a custom xml layout file with GuidedStepSupportFragment with leanback library.
I need use the custom view into right and left both sides with some action. How can I achieve this? I am new to smart TV development.
I need some this type of more customized design :
GuidedStepFragment is composed of 2 parts, Guidance (the side at left) and Actions (the side at right). You can provide layout for both of them by overriding onProvideLayoutId inside the corresponding Stylist.
For example if you want to change Guidance you can use this code:
#Override
public GuidanceStylist onCreateGuidanceStylist() {
return new GuidanceStylist() {
#Override
public int onProvideLayoutId() {
// return your cutom layout
return R.layout.layout_custom_guidance;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Guidance guidance) {
View guidanceView = super.onCreateView(inflater, container, guidance);
// You can access Views here
return guidanceView;
}
};
}
Actions part consists of several GuidedAction item, and for each you can provide the layout in a similar way:
#Override
public GuidedActionsStylist onCreateActionsStylist() {
return new GuidedActionsStylist() {
#Override
public int onProvideItemLayoutId() {
// return your custom layout for each GuidedAction item
return R.layout.layout_custom_action_item;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent) {
ViewHolder viewHolder = super.onCreateViewHolder(parent);
// Access Views here
return viewHolder;
}
};
}
For your specific Actions side you can insert one Action with your intended layout.
I am using a DialogFragment to display a 'modal' bottom sheet menu (more info here: https://material.io/develop/android/components/bottom-sheet-dialog-fragment/). Since it contains a kind of context menu for the items contained in a RecyclerView, it may be shown multiple times during runtime.
However, always DialogFragment.show() is called, Fragment.onCreateView() is also called, which leads to layout inflation, which can(?) be considered as a 'heavy' task to be computed in the UI thread, which I want to avoid for performance reasons. So to avoid layout inflation every time the DialogFragment is shown, I created a ViewGroup member object pointing to the View being returned Fragment.onCreateView() in order to be reused, like this:
public class BottomMenu extends BottomSheetDialogFragment {
private ViewGroup mLayout;
private TextView mLabel;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
if (mLayout == null) {
mLayout = (ViewGroup) LayoutInflater.from(getContext()).inflate(R.layout.bottom_sheet, container, false);
mLabel = mLayout.findViewById(R.id.bottom_sheet_label);
}
return mLayout;
}
#Override
public void onDismiss(#NonNull DialogInterface dialog) {
super.onDismiss(dialog);
// The view cannot be reused if it's already attached to the previous parent view
((ViewGroup) mLayout.getParent()).removeView(mLayout);
}
public void setLabel(String label) {
mLabel.setText(label)
}
}
But once used for the first time, such view must be detached from the Fragment container view to be reused (see onDismissed() overriden method on posted snippet), which seems like a nasty workaround
So I post this question to check if anyone knows a better approach to reuse the layout for the same Fragment
More details here:
public class ActivityMain extends AppCompatActivity {
private BottomMenu mBottomMenu;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
[...]
mBottomMenu = new BottomMenu();
}
#Override
public boolean onLongClick(View v) {
mBottomSheet.setLabel(label);
// The following calls onCreateView() in Fragment, so try to return
// there the previously inflated layout, if any
mBottomSheet.show(getSupportFragmentManager(), "TAG?");
return true;
}
}
It is already a nice practice as long as you don't surrender to any possible bugs.. However there are one or two things I want to let you know about resuing dialogFragment.
public class BottomMenu extends BottomSheetDialogFragment {
private ViewGroup mLayout;
private TextView mLabel;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
if (mLayout == null) {
mLayout = (ViewGroup) LayoutInflater.from(getContext()).inflate(R.layout.bottom_sheet, container, false);
mLabel = mLayout.findViewById(R.id.bottom_sheet_label);
} else if(mLayout.getParent()!=null) { // it's not a lot of code. just a few lines……
((ViewGroup)mLayout.getParent()).removeView(mLayout);
}
return mLayout;
}
}
One thing is about nested fragments. When the dialogFragment hold a viewpager and the viewpager have serveral sub-fragments, you must reset the viewpager's adapter on the reusing-call of onCreateView. The reason is that after closing the dialogFragment, the old fragmentManager returned by getChildFragmentManager() is no longer valid, and it should be updated.
... onCreateView(...)
if (mLayout == null) {
...
} else {
...
viewpager.setAdapter(new MyFragmentAdapter(getChildFragmentManager(), fragments));
}
If this step is omitted, you may observe strange behaviours when reusing the dialogFragment, such as recyclerviews in the sub-fragments stop updating in response to NotifyDatasetChanged, but if you scroll it, it will update.
Another thing is that I tend to use WeakRefernce to hold the dialogFragment to be reused. I even have an array of them.
In java applications, if you don't use similar mechanism, you can see rapid surge in memory usage when the user open and close the same dialog again and again. So at least it's not a bad practice to reuse dialogs when it's necessary.
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.
I've setup a tabhHost in my program with 3 tabs each with a fragment in its content that contains a textView. I've set a button in app that is supposed to update the content of every tab. However the problem i am now facing is that if i change a tab its content gets forgotten and new tab has no value aswell unless i click the button again. Each tab content has a different class but in each of them the class just returns the view with textview in it. I assumed that the values reset on each view inflate however i cannot find a reasonable way to make it work as i intend to it.
Here is the part of the code with the method ran by my button:
public void getNum(View view) {
proteinNeeded = weightNum.getValue() * FirstActivity.weightMultiplier;
carbohydrateNeeded = weightNum.getValue() * 5;
switch (weightMultiplier) {
case 2: {
resultTxt = String.format("Zapotrzebowanie:%nBiałko - %dg.%nWęglowodany - %dg.%n",
FirstActivity.proteinNeeded, FirstActivity.carbohydrateNeeded);
FragmentTab.tv.setText(resultTxt);
FragmentTab2.dietTxt = String.format("text1");
FragmentTab2.tv.setText(FragmentTab2.dietTxt);
FragmentTab3.foodTxt = String.format("text2");
FragmentTab3.tv.setText(FragmentTab3.foodTxt);....
And here is the code from FragmentTab.java, each tab has more or less same code so i'll post only this one for now:
public class FragmentTab extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public static View v;
public static TextView tv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_layout, container, false);
tv = (TextView) v.findViewById(R.id.textResult);
if (tv != null) {
tv.setText("nothing has been input yet");
}
return v;
}
}
TL;DR - How do I save my values in textView in such a way that if my text gets updated it won't revert to default values after the view gets refreshed?
An option to solve your problem is to use SQLite Database to save your data, and fetch it from database whenever you return to that tab.
You can refer to this link. Saving Data in SQL Databases.
For other android storage options, refer to this series of videos. Android Data Storage Options.
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.