I want to add elements into my layout automatically, how do I do that? For example a textview appears when a user clicks a button
To add a TextView or any other view in Android you must add the view you want to a view that support addition, one example is the LinearLayout.
If you have this layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lnrRootView"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
And then in you Activity add a TextView programaticlly to your LinearLayout.
public class MainActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
var linearLayout = FindViewById<LinearLayout>(Resource.Id.lnrRootView);
var textView = new TextView(this);
textView.Text = "Added programaticlly";
linearLayout.AddView(textView);
}
}
You will get something like this:
Much depends on what you're trying to accomplish. You could simulate adding to layout by turning visibility of elements after certain event, eg. button click.
If you want to add elements dynamically during runtime, consider using
ObservableCollection<T>
Link: https://developer.xamarin.com/api/type/System.Collections.ObjectModel.ObservableCollection%601/
I don't know Xamarin.Android very well but I think the right way is to add controls to layout with "IsVisible = false", then set IsVisible = true.
Otherwise you can take a look to
LinearLayout principalview = FindViewById(Resource.Id.mainlayout);
LinearLayout.LayoutParams parametros = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MatchParent, LinearLayout.LayoutParams.MatchParent);
var valueB = new Button(this);
valueB.Text = "Teste";
valueB.SetBackgroundColor(Color.Aqua);
principalview.AddView(valueB, parametros);
OR
var layout = new LinearLayout (this);
layout.Orientation = Orientation.Vertical;
var aLabel = new TextView (this);
aLabel.Text = "Hello, World!!!";
var aButton = new Button (this);
aButton.Text = "Say Hello!";
aButton.Click +=(sender, e) =>
{aLabel.Text="Hello Android!";};
layout.AddView (aLabel);
layout.AddView (aButton);
SetContentView (layout);
Related
I made a Custom Layout to add a badge to a tab on Android. This badge is a TextView.
How do I bind this component?
It's possible?
My custom badge layout:
<LinearLayout
android:id="#+id/badgeCotainer"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginStart="90dp"
android:background="#drawable/notifications_background"
android:gravity="center"
android:layout_gravity="right"
android:minWidth="16dp">
<TextView
android:id="#+id/badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="#011f7a"
android:textSize="10sp"
android:text="0"
app:MvxBind="Text ContMaterial"/>
</LinearLayout>
My Activity: use MvxViewPagerFragmentInfo
private void InitTabs()
{
var viewPager = FindViewById<ViewPager>(Resource.Id.materiais_viewpager);
if (viewPager != null)
{
var fragments = new List<MvxViewPagerFragmentInfo>
{
new MvxViewPagerFragmentInfo("Requisição",
typeof(CadastraRequisicaoFragment), ViewModel),
new MvxViewPagerFragmentInfo("Materiais",
typeof(ListaMateriaisFragment), ViewModel),
};
viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(this, SupportFragmentManager, fragments);
}
var tabLayout = FindViewById<TabLayout>(Resource.Id.requisicao_tabs);
tabLayout.SetupWithViewPager(viewPager);
tabLayout.GetTabAt(1).SetCustomView(Resource.Layout.tab_header_badge);
}
On view Model I used raisedPropertyChanged()
Badge appears normally, just don't change value.
Tablayout
Out of the box there is nothing in mvvmcross to bind the content of a TabLayout when you provide a custom view. You could however try something custom using MvxFrameControl
Basically, replace your LinearLayout by the MvxFrameControl, then after
tabLayout.SetupWithViewPager(viewPager);
inflate your custom view using the BindingInflate method, and set a value to your MvxFrameControl's BindingContext, then set your custom tablayout view with the result that operation.
That might do the trick.
Another way to do it, is to listen to your ViewModel's "PropertyChanged" events in your Activity, and manually make changes to your tab layouts when it applies.
I have an android ProgressBar which is indeterminate so it is simply a revolving circle animation.
It starts off displaying fine, but after I set the visibility of its parent (overlayLayout) to either gone or invisible and then set it back to visible later on, the progress bar is unseen?
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/overlayLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:gravity="center" >
<TextView
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:textAlignment="center"
android:layout_margin="10dp"
android:layout_height="wrap_content"
android:id="#+id/overlayLabelText" />
<ProgressBar
android:id="#+id/overlayProgressBar"
android:layout_below="#id/overlayLabelText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foregroundGravity="center"
android:indeterminate="true" />
</RelativeLayout>
EDIT:
I'm unsure if the view is included but the progress bar is just not rendered or whether the ProgressBar view itself is completely excluded as I can't access the UI view hierarchy.
So far I have tried:
ProgressBar.Enabled = true;
ProgressBar.ForceLayout();
ProgressBar.Invalidate();
ProgressBar.SetProgress(0, true);
ProgressBar.Visibility = ViewStates.Visible;
But have had no breakthroughs yet.
EDIT 2:
Thankyou everyone for your help so far. I have switched to creating the layout programatically - this is my full code:
overlay = new RelativeLayout(mainActivity)
{
LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent)
};
overlay.SetBackgroundColor(Color.WhiteSmoke);
overlay.SetGravity(GravityFlags.Center);
description = new TextView(mainActivity)
{
LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent),
Gravity = GravityFlags.Center,
TextSize = 18,
Id = 1523112
};
description.Text = "Waiting for GPS";
description.SetBackgroundColor(Color.Aqua);
progressBar = new ProgressBar(mainActivity)
{
Indeterminate = true,
};
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
lp.AddRule(LayoutRules.Below, description.Id);
progressBar.LayoutParameters = lp;
progressBar.SetBackgroundColor(Color.Red);
container.AddView(overlay);
overlay.AddView(description);
overlay.AddView(progressBar);
With the two hiding and showing methods:
private void OnGpsUpdate()
{
overlay.Visibility = ViewStates.Gone;
}
private void NoGPS()
{
description.Text = "Waiting for GPS";
overlay.Visibility = ViewStates.Visible;
}
When the layout is first rendered, before its hidden for the first time:
(I screenshotted at a bad time, but blue drawing shows where the circle is moving around its loading animation)
After its been hidden and shown again, the progressBar loading view is there but there's no loading circle anymore:
I am starting to think it may just be a problem with my android emulator? Nope, same problem when testing on my physical phone. Text view still shows fine, its just the progress bar doesnt show?
SOLUTION
I don't fully understand it, seeing as everything else seemed to work except the progressBar, but a solution came from wrapping my visibility calls in a RunOnUIThread() call.
Few points
Based on how the problem was described, there is a need for you to show the code snippet you used for hiding/showing the overlayLayout
Recommendations
If you're only concerned with how the progress bar should behave in terms of hiding/showing, there's no need for this snippet:
ProgressBar.Enabled = true;
ProgressBar.ForceLayout();
ProgressBar.Invalidate();
ProgressBar.SetProgress(0, true);
ProgressBar.Visibility = ViewStates.Visible;
You just need to control the root layout which has the id of overlayLayout
private RelativeLayout overlayLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
// Instantiate the layout
overlayLayout = findViewById(R.id.overlayLayout);
// Do the logic how you inflate/show the layout
...
// Hide the overlay layout
overlayLayout.setVisibility(View.GONE);
// Show the overlay layout
overlayLayout.setVisibility(View.VISIBLE);
}
Decide on the visibility value, for this scenario, I'd recommend View.GONE rather than View.INVISIBLE
Read more on:
https://developer.android.com/reference/android/view/View.html#GONE
https://developer.android.com/reference/android/view/View.html#INVISIBLE
http://tips.androidgig.com/invisible-vs-gone-view-in-android/
The solution was to add a RunOnUIThread like so:
private void OnNewGPS()
{
mainActivity.RunOnUiThread(() =>
{
overlay.Visibility = ViewStates.Gone; });
}
private void NoGPS()
{
mainActivity.RunOnUiThread(() =>
{
overlay.Visibility = ViewStates.Visible;
});
}
Where mainActivity is a reference to the Activity the views are running in.
I wrote a demo based on your code. And to test it, I added a button to control the show and hide of the layout.
You may try this:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
// Instantiate the layout
overlayLayout = FindViewById<LinearLayout>(Resource.Id.overlayLayout);
progressBar = FindViewById<ProgressBar>(Resource.Id.overlayProgressBar);
description = FindViewById<TextView>(Resource.Id.textView1);
description.Text = "Waiting for GPS";
description.SetBackgroundColor(Color.Aqua);
progressBar.SetBackgroundColor(Color.Red);
switchBtn = FindViewById<Button>(Resource.Id.switchButton);
switchBtn.Click += SwitchBtn_Click;
overlayLayout.Visibility = Android.Views.ViewStates.Visible;
isShown = true;
}
private void SwitchBtn_Click(object sender, System.EventArgs e)
{
if (isShown)
{
overlayLayout.Visibility = Android.Views.ViewStates.Gone;
isShown = false;
switchBtn.Text = "Show";
}
else {
overlayLayout.Visibility = Android.Views.ViewStates.Visible;
isShown = true;
switchBtn.Text = "Hide";
}
You can download the demo from this
to hide layout:
findViewById(R.id.overlayLayout).setVisibility(View.GONE);
to display it again :
findViewById(R.id.overlayLayout).setVisibility(View.VISIBLE);
I've been looking at the Playground project on MvvmCross (https://github.com/MvvmCross/MvvmCross/tree/develop/Projects/Playground)
The way to have a fragment loaded into the tabs is to set the attribute the following way:
[MvxTabLayoutPresentation(TabLayoutResourceId = Resource.Id.tabs, ViewPagerResourceId = Resource.Id.viewpager, Title = "Tab 1", ActivityHostViewModelType = typeof(TabsRootViewModel))]
[MvxTabLayoutPresentation(TabLayoutResourceId = Resource.Id.tabs, ViewPagerResourceId = Resource.Id.viewpager, Title = "Tab 1", FragmentHostViewType = typeof(TabsRootBView))]
[Register(nameof(Tab1View))]
public class Tab1View : MvxFragment<Tab1ViewModel>
My questions is, besides the title that can be specified on the MvxTabLayoutPresentation, how can I add and icon to each one of the tabs?
That is not provided out-of-the-box and it's more about TabLayout customization.
You can achieve it like this.
Create a CustomView for your tab layout item, myCustomTab.axml:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/txtTab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textColor="#FFFFFF"
android:textSize="12"
android:textStyle="bold" />
Then in your view that has the TabLayout you configure it on the OnCreate / OnCreateView:
var tabLayout = view.FindViewById<TabLayout>(Resource.Id.tabs);
var customTab = inflater.Inflate(Resource.Layout.myCustomTab, null);
customTab.Text = "MyText";
// this sets the icon above the text
customTab.SetCompoundDrawablesWithIntrinsicBounds(0, Resource.Drawable.my_icon, 0, 0);
tabLayout.GetTabAt(0).SetCustomView(customTab);
Obviously you have to do this as many times as tab layout items you have.
Furthermore using this you can add any customization to your tab layout items.
Source (in java): https://mobikul.com/make-custom-tabs-icons-android/
HIH
So I'm a bit of a newb in Android. I've read a few tutorials but found it extensively complicated to understand. I was hoping someone can help me understand on how to implement Animations to views on the current context I'm working on (noob friendly).
Let's say this is my .axml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/top_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:orientation="vertical" />
Now this is my activity (Not exactly but enough information to know what I want to do:
private LinearLayout _topContainer;
private IDictionary<string, FrameLayout> _framelayoutViewsDictionary = new Dictionary<string, FrameLayout>();
private LinearLayout.LayoutParams layoutParams;
protected override void OnCreate(Bundle bundle)
{
//SetContentView and other stuff...
layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent, 1);
_topContainer = FindViewById<LinearLayout>(Resource.Id.top_container);
}
public void CreateFirstVideoPlayer
{
_framelayoutViewsDictionary.Add(Constants.Views.TOP_FRAMELAYOUT, new FrameLayout(this)
{
Id = 1,
LayoutParameters = layoutParams
});
var fragmentManager = FragmentManager.BeginTransaction();
fragmentManager.Add(_framelayoutViewsDictionary[Constants.Views.TOP_FRAMELAYOUT].Id, /*Create New MediaPlayer Here*/, Constants.FragmentTag.TOP_FRAGMENT);
fragmentManager.Commit();
_topContainer.AddView(_framelayoutViewsDictionary[Constants.Views.TOP_FRAMELAYOUT]);
}
public void CreateSecondVideoPlayer
{
_framelayoutViewsDictionary.Add(Constants.Views.BOTTOM_FRAMELAYOUT, new FrameLayout(this)
{
Id = 2,
LayoutParameters = layoutParams
});
var fragmentManager = FragmentManager.BeginTransaction();
fragmentManager.Add(_framelayoutViewsDictionary[Constants.Views.BOTTOM_FRAMELAYOUT].Id, /*Create New MediaPlayer Here*/, Constants.FragmentTag.BOTTOM_FRAGMENT);
fragmentManager.Commit();
_topContainer.AddView(_framelayoutViewsDictionary[Constants.Views.BOTTOM_FRAMELAYOUT]);
}
As you can see. I'm programmatically creating a new FrameLayout, adding a fragment on top. And then putting that FrameLayout on top view which is a LinearLayout. Now when I add the second FrameLayout. The first FrameLayout is halved and the second one is added. So now each FrameLayout is taking 50:50 space. So what I want to do is. When the second FrameLayout is added, I want the first FrameLayout to animate so it slowly moves upwards to the top half of the screen instead of instantly appearing on the top. And when I remove the second FrameLayout the first FrameLayout will slowly animate back to the centre of the screen.
Hope this all makes sense. If you need more info please comment!
Using the Support Libraries to perform a fragment slide in/out is as easy as setting the Fragment's custom animations to the built-in resource abc_slide_in_bottom and abc_slide_out_bottom animations.
Example:
SupportFragmentManager
.BeginTransaction()
.SetCustomAnimations(
Resource.Animation.abc_slide_in_bottom,
Resource.Animation.abc_slide_out_bottom,
Resource.Animation.abc_slide_in_bottom,
Resource.Animation.abc_slide_out_bottom)
.AddToBackStack(count.ToString())
.Add(Resource.Id.linearLayout1, new AFragmentSubClass(), count.ToString())
.Commit();
I'm trying to add a list of cards into a scroll view, using A separate xml file as my layout.
However on button press I get the following error:
System.NullReferenceException: Object reference not set to an instance of an object
I can add the text just fine without using the Card.xml layout, its when I use that as my layout that I get the error.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
Button buttonWhite = FindViewById<Button>(Resource.Id.button2);
//On button click, loop though dealt hand of cards and add each to Scrollveiw using Card layout file
buttonWhite.Click += delegate
{
HorizontalScrollView ScrollView = (HorizontalScrollView)FindViewById(Resource.Id.horizontalScrollView1);
//create layout from Cardlayout file
LinearLayout Test_card = (LinearLayout)FindViewById(Resource.Layout.Card);
//loopthough Players hand and use text to add to card layout then add layout with text to scrollview
foreach (Card Test in p.hand)
{
//create new textview
TextView Test_Text = new TextView(this);
//set new textviews text value to card text
Test_Text.Text = Test.text;
//addview to layout
Test_card.AddView(Test_Text);
}
//add layout to scrollview
ScrollView.AddView(Test_card);
};
}
You should inflate the Card resource layout, it is not in your current context. So you should replace:
LinearLayout Test_card = (LinearLayout)FindViewById(Resource.Layout.Card);
with (Java):
LinearLayout Test_card = (LinearLayout) getLayoutInflater().inflate(Resource.Layout.Card);
C# (maybe):
LinearLayout Test_card = (LinearLayout) this.LayoutInflater.Inflate(
Resource.Layout.Card ...);