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 ...);
Related
I am making an app for UWP on Visual Studio that uses the Windows UI Library for the tab view component. I was following the documentation and it gives the following code to use:
xaml:
<muxc:TabView AddTabButtonClick="TabView_AddTabButtonClick" TabCloseRequested="TabView_TabCloseRequested"/>
c#:
// Add a new Tab to the TabView
private void TabView_AddTabButtonClick(muxc.TabView sender, object args)
{
var newTab = new muxc.TabViewItem();
newTab.IconSource = new muxc.SymbolIconSource() { Symbol = Symbol.Document };
newTab.Header = "New Document";
// The Content of a TabViewItem is often a frame which hosts a page.
Frame frame = new Frame();
newTab.Content = frame;
frame.Navigate(typeof(Page1));
sender.TabItems.Add(newTab);
}
// Remove the requested tab from the TabView
private void TabView_TabCloseRequested(muxc.TabView sender, muxc.TabViewTabCloseRequestedEventArgs args)
{
sender.TabItems.Remove(args.Tab);
}
I added that code to my project and and at first glance it looks normal.
However when try to interact, there are problems. I can only create a new tab if I click at the very bottom edge of the " + " icon. I also cant exit any tabs or interact with them.Here's a gif of my problem:
https://im7.ezgif.com/tmp/ezgif-7-565b1f0b4531.gif
Does anybody have a fix for this?
Thanks for any help
You need to create a TabStripHeader and TabStripFooter.
TabStripHeader's children is Grid and set name it to ShellTitlebarInset,
TabStripFooter's children is Grid and set name it to CustomDragRegion
and set background to Transparent for both.
Use CustomDragRegion as Title Bar.
Like Example:-
<muxc:TabView>
<muxc:TabView.TabStripHeader>
<Grid x:Name="ShellTitlebarInset" Background="Transparent" />
</muxc:TabView.TabStripHeader>
<muxc:TabView.TabStripFooter>
<Grid Grid.Column="3" x:Name="CustomDragRegion" Background="Transparent" />
</muxc:TabView.TabStripFooter>
</muxc:TabView>
And C# Example:-
public MainPage()
{
this.InitializeComponent();
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.ExtendViewIntoTitleBar = true;
coreTitleBar.LayoutMetricsChanged += CoreTitleBar_LayoutMetricsChanged;
Window.Current.SetTitleBar(CustomDragRegion);
}
private void CoreTitleBar_LayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
if (FlowDirection == FlowDirection.LeftToRight)
{
CustomDragRegion.MinWidth = sender.SystemOverlayRightInset;
ShellTitlebarInset.MinWidth = sender.SystemOverlayLeftInset;
}
else
{
CustomDragRegion.MinWidth = sender.SystemOverlayLeftInset;
ShellTitlebarInset.MinWidth = sender.SystemOverlayRightInset;
}
CustomDragRegion.Height = ShellTitlebarInset.Height = sender.Height;
}
Note: To ensure that the tabs in the title bar are not occluded by shell content, you must account for left and right overlays. In LTR layouts, the right inset includes the caption buttons and the drag region. The reverse is true in RTL. The SystemOverlayLeftInset and SystemOverlayRightInset values are in terms of physical left and right, so reverse these too when in RTL.
Click Here for More Information
I'm trying to dynamically add new views to an existing relative layout through C# code in Xamarin.Android. I haven't find any solution on how to position child views in the relative layout. Right now they are just placed at their default location in the top left corner of the application. I've seen solutions to this problem in Xamarin.Forms but not Xamarin.Native.
I have been able to specify width and height of the view through passing a ViewGroup.LayoutParams to the AddView method of the relative layout object, but there are no constructors etc of that class that handle position.
var root = FindViewById<RelativeLayout>(Resource.Id.relativeLayout1);
var tv = new TextView(this);
root.AddView(tv, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WrapContent,
ViewGroup.LayoutParams.WrapContent));
I want to be able to use "layout_below" on the tv view through C# and not statically through AXML.
You just need to add a rule to the layout parameters using AddRule() to place the view below the other one. Here is an example I put together that adds two TextViews, with the first being placed at the top (using .AlignTop) and the 2nd being placed below the first (using .Below).
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
RelativeLayout rl = new RelativeLayout(this);
TextView tv1 = new TextView(this) {Id = View.GenerateViewId(), Text = "TextView #1"};
RelativeLayout.LayoutParams parms1 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
parms1.AddRule(LayoutRules.AlignTop);
tv1.LayoutParameters = parms1;
rl.AddView(tv1);
TextView tv2 = new TextView(this) {Id = View.GenerateViewId(), Text = "TextView #2"};
RelativeLayout.LayoutParams parms2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
parms2.AddRule(LayoutRules.Below, tv1.Id);
tv2.LayoutParameters = parms2;
rl.AddView(tv2);
SetContentView(rl);
}
Screenshot
I want every page in my app to have a transparent toolbar at the top, and a background image that covers the entire page.
In the App.xaml.cs I have written the following:
MainPage = new NavigationPage(new MDMaster())
{
BarBackgroundColor = Color.Transparent,
BackgroundImage = "background_1.png"
};
This will correctly make the toolbar transparent, however the background image is not shown. It's possible for me to add a background color but not a background image.
MDMaster is the master component of a MasterDetailPage. On the MDMaster page I set the Detail page like so:
Detail = new NavigationPage(new ProfilePage())
{
BarBackgroundColor = Color.Transparent,
BackgroundImage = "background_1.png"
};
This does not even show the background image either.
On the ProfilePage, I can write:
public ProfilePage()
{
InitializeComponent();
this.BackgroundImage = "background_1.png";
}
This will show the background image, however it will not cover the area behind the toolbar even though it's transparent. It ends up looking like this:
First, as #Yuri S suggested, you don't need to wrap your MasterDetailPage with NavigationPage. Just set the MasterDetailPage as the MainPage is OK.
Then when you are setting the background image to the root MasterDetailPage, the reason why the background image is not showing is because the top NavigationPage is not transparent and it's hiding the background image.
So to fix the problem, you need to set the BackgroundColor of NavigationPage to transparent too:
public App()
{
InitializeComponent();
MainPage = new MasterDetailPage()
{
Master=new MainPage(),
Detail=new NavigationPage(new Detail())
{
BarBackgroundColor=Color.Transparent,
BackgroundColor=Color.Transparent
},
BackgroundImage="tianyuan.jpg"
};
}
Then it will show like this:
If you don't want your status bar to show like above, you can set it manually in Droid project:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
//set the status bar color
Window.SetStatusBarColor(Android.Graphics.Color.Black);
}
}
And it will show like this:
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);
I can create a new element of type Page in code behind, but I want to add children elements of type UIElement as I would to a Grid like: myGrid.Children.Add(myUIElement);
I don't have the Children property and setting the Content property does not work.How can I achieve this?
UPDATE:
This is what I have so far, but does not work:
Page myNewPage = new Page();
Grid myGrid = new Grid();
TextBlock myText = new TextBlock();
myText.Text = "I am a TextBlock!";
myGrid.Children.Add(myText);
myNewPage.Content = myGrid;
Frame.Navigate(myNewPage.GetType());
A Page can host a single UIElement in its Content property. To add several children, you have to do it like you would do it in XAML: add a panel that can contain and layout several children and add your elements to that panel.
In your question you talk about a grid called myGrid. You could add and layout your items in myGrid and then set myGrid as yourPage.Content.
Your code correctly builds the page. The problem with your code is that your Frame is navigating to a new instance of Page that is not the one that you created. Frame creates a new instance of the type that you pass as a parameter.
If you want to create a page fully in code, you can simply create class that extends Page and build the page in its constructor:
public class MyPage : Page
{
public MyPage()
{
this.BuildPage();
}
private void BuildPage()
{
var panel = new StackPanel();
panel.Children.Add(new TextBlock { Text = "Hello" });
panel.Children.Add(new TextBlock { Text = "World" });
this.Content = panel;
}
}
That's, after all, what the InitializeComponent method does in pages created in XAML.