how can I change the style of the tab title? The most important thing is, that the titles not cutted off like at the screenshot. So I have to change the size of the titles.
I started creating a Custom Renderer for tabbedpage, but I don't know how to go on.
Xaml:
<custom:CustomTabbedPage...
Forms:
public class CustomTabbedPage : TabbedPage...
Forms.Droid
public class CustomTabbedPageRenderer : TabbedPageRenderer
The TabbedPage has NavigationPages with ContentPages.
If you need further information, let me know. Thank you.
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TabbedPageWithNavigationPage;assembly=TabbedPageWithNavigationPage"
x:Class="TabbedPageWithNavigationPage.MainPage">
<NavigationPage Title="Start" Icon="start.png">
<x:Arguments>
<local:StartPage />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="Symptom-Tagebuch" Icon="tagebuch.png">
<x:Arguments>
<local:TagebuchPage />
</x:Arguments>
</NavigationPage>
...
It seems that the default title style of NavigationPage behaviors different on different size of device. By my side on 7" KitKat emulator it looks so:
and on 5" KitKat emulator it looks so:
Or it could be the version problem which cause the behavior of this NavigationPage by my side so different from yours, I can't reproduce yout issue. Anyway, if you want to customize the layout of your NavigationPage, you can create a custom render for your android platform. For more information, you can refer to the official document Customizing Controls on Each Platform, and if you're looking for a demo, there are discussions on the official forum about customize the title font of NavigationPage you may also take a look: Discussion 1 and Discussion 2.
Another possible solution to your problem is that I think you can change the NavigationPage to ContentPage, and change your sub pages to content view, and by doing this, you can refer to Xamarin.Forms: Can I embed one ContentPage or ContentView into another ContentPage.
According to your description, maybe the first solution by creating your own custom render is more suitable for your scenario.
You can find the textview of title through TabLayout view children in CustomRendered and change font style
[assembly: ExportRenderer(typeof(MainPage), typeof(BottomTabbedPageRenderer))]
namespace Daddy.Droid
{
public class BottomTabbedPageRenderer : TabbedPageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
if (e.NewElement == null || e.OldElement != null)
return;
TabLayout tablayout = (TabLayout)ViewGroup.GetChildAt(1);
Android.Views.ViewGroup vgroup = (Android.Views.ViewGroup)tablayout.GetChildAt(0);
for (int i = 0; i < vgroup.ChildCount; i++)
{
Android.Views.ViewGroup vvgroup = (Android.Views.ViewGroup)vgroup.GetChildAt(i);
Typeface fontFace = Typeface.CreateFromAsset(this.Context.Assets, "IranSans.ttf");
for (int j = 0; j < vvgroup.ChildCount; j++)
{
Android.Views.View vView = (Android.Views.View)vvgroup.GetChildAt(j);
if (vView.GetType() == typeof(Android.Support.V7.Widget.AppCompatTextView) || vView.GetType() == typeof(Android.Widget.TextView))
{
//here change textview style
TextView txtView = (TextView)vView;
txtView.TextSize = 14f;
txtView.SetTypeface(fontFace, TypefaceStyle.Normal);
}
}
}
}
}
}
Related
I'm using WEB API to retrieve coordinates and display them as polygons on my Map.
Now I want to make those Polygons when they clicked to display a pop with more information from the API.
My Xaml:
<maps:Map x:Name="map">
<x:Arguments>
<maps:MapSpan>
<x:Arguments>
<maps:Position>
<x:Arguments>
<x:Double>-30.241943</x:Double>
<x:Double>25.771944</x:Double>
</x:Arguments>
</maps:Position>
<x:Double>
20
</x:Double>
<x:Double>
20
</x:Double>
</x:Arguments>
</maps:MapSpan>
</x:Arguments>
<maps:Map.MapElements>
</maps:Map.MapElements>
</maps:Map>
</StackLayout>
then my C# code for adding Polygons:
foreach (var tempList in AlertsList)
{
string alertType = tempList.AlertType;
if (alertType == "Advisory")
{
polygon = new Polygon();
polygon.StrokeColor = Color.FromHex("ffff00");
polygon.FillColor = Color.FromHex("ffff00");
polygon.StrokeWidth = 5f;
foreach (var Poly in tempList.Polygon)
{
float Lat = float.Parse(Poly[0]);
float Long = float.Parse(Poly[1]);
polygon.Geopath.Add(new Position(Lat, Long));
}
// add to map
map.MapElements.Add(polygon);
}
}
Add Gesture recognizer to your view and display the popup based on your requirement. You can add Gestures to any view in Xamarin Forms.
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (s, e) => {
// handle the tap to display the popup here
};
[YourView].GestureRecognizers.Add(tapGestureRecognizer);
If you want to display a simple alert dialog then you can use the DisplayAlert in Xamarin forms to achieve the result. Refer the documentation here for more details.
If you wish to display customized popup based on your UI requirements, then there is an excellent open source plugin (Rg.Plugins.Popup) available for it. You can download the NuGet here. It has various examples as well for you to achieve what you want.
I hope that helps you.
What is the optimal solution to design big screens and tablets?
the view looks good on phones but when on tablets or big screens, the buttons and text entries looks stretched and unprofessional.
I can add padding but is there a better solution than that?
I see that the new pre-release of Xamarin forms version 3 doesn't support #medai. But does it account for this issue in another way?
The Xamarin.Forms Page class has a SizeChanged event we can use to determine the available screen-size at runtime. We can adjust the UI based on the Width or Height of the screen.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
SizeChanged += MainPageSizeChanged;
}
void MainPageSizeChanged(object sender, EventArgs e)
{
imgMonkey.WidthRequest = Math.Min(this.Width, 400);
}
}
And Xamarin.Forms provides a static Idiom property on the Device class that we can use to check the device type.
if (Device.Idiom == TargetIdiom.Phone)
{
buttonAbout.HeightRequest = 25;
buttonAbout.WidthRequest = 40;
}
else
{
buttonAbout.HeightRequest = 40;
buttonAbout.WidthRequest = 70;
}
Detail refer to Adaptive UI with Xamarin.Forms.
You can use VisualStateManager to achieve this task.
Find more information on how to get started at https://xamarinhelp.com/visualstatemanager-xamarin-forms-phase-1/
I want to open an Android activity for Android devices and iOS screen for iOS devices from login screen. The code of the login screen, I have written is in shared portable code Area. I have used interface and #if ANDROID #endif, but it is also not working.
Android screen will only contain a textview and an iOS screen will contain a Image. This is my Login Page in portable folder
namespace DemoApp
{
public class HomePage : ContentPage
{
public HomePage()
{
var title = new Label
{
Text = "Welcome to CloudCakes",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
var email = new Entry
{
Placeholder = "E-Mail",
};
var password = new Entry
{
Placeholder = "Password",
IsPassword = true
};
var login = new Button
{
Text = "Login"
};
// With the `PushModalAsync` method we navigate the user
// the the orders page and do not give them an option to
// navigate back to the Homepage by clicking the back button
login.Clicked += (sender, e) =>
{
App.UserPreferences.Open();
// await Navigation.PushModalAsync(new MainPage());
};
Content = new StackLayout
{
Padding = 30,
Spacing = 10,
Children = { title, email, password, login}
};
}
}
}
And, this is the page in Droid folder where I want to navigate on clicking login button
name space
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Page1 : IUserPreferences
{
public Page1()
{
InitializeComponent();
}
public void Open()
{
var title = new Label
{
Text = "Welcome to Xamarin Forms IOS Screen!!",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
Content = new StackLayout
{
Padding = 30,
Spacing = 10,
Children = { title }
};
}
}
}
Open is a method of interface which is present in the portable folder.
I assume that you're using Xamarin.Forms, so what you need to do is actually quite easy to achieve.
Instead of having a separate page for each platform, create one new XAML page with the following code:
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="YourApp.Views.MainPage">
<ContentView>
<OnPlatform x:TypeArguments="View">
<OnPlatform.iOS>
<Image Source="something.png" />
</OnPlatform.iOS>
<OnPlatform.Android>
<Label Text="Android" />
</OnPlatform.Android>
</OnPlatform>
</ContentView>
</ContentPage>
This way you can control what to have on the page for each platform.
To navigate to MainPage from your LoginPage, you need to implement the Clicked event (or preferrably use Commands) in the code behind (MainPage.xaml.cs) and do the navigation there:
private void SomeButton_Clicked(object sender, System.EventArgs e)
{
await this.Navigation.PushAsync(new MainPage());
}
In the long run, you should look into doing all this outside the code behind with ViewModel's and Commands.
Edit: Since the first solution didn't work for you, here's what to do:
1) Subclass ContentPage in your core project.
public class MainPage : ContentPage { }
2) Implement a PageRenderer for each platform separately. You'll be able to use native layout definition for your pages as you mentioned.
There's a great article on the Xamarin blog on how to achieve this. You can also find the source code on GitHub.
I'm using a TabbedPage as my MainPage of my Xamarin.Forms app (Xamarin.Forms Version: 2.3.5.239-pre3). My MainActivity inherits from FormsAppCompatActivity.
There are four pages of type ContentPage added to the TabbedPage like:
<TabbedPage ... >
<pages:FirstPage Title="Testpage1" Icon="icon.png" />
<pages:SecondPage Title="Testpage2" Icon="icon.png" />
<pages:ThirdPage Title="Testpage3" Icon="icon.png" />
<pages:FourthPage Title="Testpage3" Icon="icon.png" />
</TabbedPage>
However, the tabs are displayed like:
Now I need to change the font size of the title property, so the whole title will be displayed. Whats the best way to do this? I tried a CustomRenderer but I couldn't figure out how to access the tab-items.
I tried:
[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTab))]
namespace AdvancedForms.Droid.CustomRenderer
{
public class CustomTab : TabbedRenderer
{
protected override void DispatchDraw(Canvas canvas)
{
base.DispatchDraw(canvas);
ActionBar actionBar = activity.ActionBar;
// Do Stuff here
}
}
}
But activity.ActionBar is always null.
You should be looking for a TabLayout, not an ActionBar. Last I checked the TabLayout is the second child in the renderer's view hierarchy so you should be able to get at it like so:
var tabLayout = (TabLayout)GetChildAt(1);
Once you have that you need to loop through the individual tabs and apply your desired font size to each tab's textview.
Helpful hint, the view hierarchy looks like this:
MsiTabbedRenderer
FormsViewPager
TabLayout
SlidingTabStrip
TabView
AppCompatImageView
AppCompatTextView
TabView
AppCompatImageView
AppCompatTextView
TabView
AppCompatImageView
AppCompatTextView
...
The method I use to generate this information is included below for your enjoyment:
public static void DebugLayout(this View self, int indent = 0)
{
// write info about me first
var indents = new string('\t', indent);
System.Diagnostics.Debug.WriteLine(indents + self.GetType().Name);
// check if I'm a view group
var vg = self as ViewGroup;
if (vg == null) return;
// enumerate my children
var children = Enumerable.Range(0, vg.ChildCount).Select(x => vg.GetChildAt(x));
// recurse on each child
foreach (var child in children)
DebugLayout(child, indent+1);
}
For Custom tab view/page i am using the xam.Tabview (Xamarin.Forms) Component and it's working as expected.
It has the support for custom header and content view.
Install Nuget: TabView Nuget
Sample: Tabview Sample
I have a Xamarin.Forms project, and I have a custom control that should open a new page when tapped. Unfortunately, nothing happens when I call Navigation.PushAsync(...);. I've read countless StackOverflow questions (such as this one) and Xamarin Forums threads and done several Google searches, but none of the solutions seem to solve my issue.
My control inherits from ContentView, as all Xamarin.Forms views
do.
src is a custom class that contains some data points that
are used by this control and EventDetailsPage.
I can confirm that the gesture does work itself, but the call to PushAsync() does nothing.
I have tried manipulating the statement in ways so that a NavigationPage is used (such that it becomes myNavigationPage.Navigation.PushAsync(new EventDetailsPage(src));).
I have also tried creating a constructor that takes a Page and uses it in away similar to the above point.
My control's constructor:
public EventControl() {
InitializeComponent();
GestureRecognizers.Add(new TapGestureRecognizer() {
Command = new Command(() => Navigation.PushAsync(new EventDetailsPage(src)))
});
}
Typically, asking a new question on StackOverflow is my last resort when nothing else that I've tried solved my problem. Any help is appreciated.
Change your App.cs like this
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());//Very important add this..
//MainPage = new MainPage(); //not like this
}
I found the problem. Keith Rome lead me to look through EventDetailsPage and I commented out a line of XAML, and that solved the problem. That line was adding a custom control to the page (not related to EventControl). I don't know if the control's definition or its custom render's definition was causing the strange behavior, but removing that line solved the issue.
Same problem for different reasons...
I got this problem, after installing updates in Visual Studio, including Xamarin.
After updating all my nuget packages, by the following (the first command to show which ones have updates), I was able to resolve the problem:
Get-Package -updates
Update-Package <package>
I suspect, removing the AppData\local\Xamarin folder (which seems to act as a cache) and letting it repopulate could also solve the problem.
I implemented AppShell class which has one input string, in order to set correct page:
public partial class AppShell : Shell
{
public AppShell(string startUpPageString = null)
{
InitializeComponent();
Page startUpPage;
if (startUpPageString == nameof(SignUpPage))
{
startUpPage = new SignUpPage();
}
else if (startUpPageString == nameof(LoginPinPage))
{
startUpPage = new LoginPinPage();
}
else
{
startUpPage = new SignUpPage();
}
ShellSection shellSection = new ShellSection();
shellSection.Items.Add(new ShellContent() { Content = startUpPage });
CurrentItem = shellSection;
RegisterRoutes();
}
private void RegisterRoutes()
{
...removed for clarity
}
}
among that, in my XAML I added some tabs (postlogin section) which are called though GoToAsync(postlogin) method:
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:login="clr-namespace:XXX.Views.Login"
xmlns:postlogin ="clr-namespace:XXX.XXX.Views.PostLogin"
x:Class="XXX.AppShell"
FlyoutBehavior="Disabled">
<ShellItem Route="postlogin">
<ShellSection Route="activity_section" Title="Activity" Icon="Activity_Menu_Icon.png">
<ShellContent Route="page1"
Title="Page1"
Icon="Pag1.png"
ContentTemplate="{DataTemplate postlogin:Page1}" />
</ShellSection>
<ShellContent Route="page2"
Title="Page2"
Icon="Pag2.png"
ContentTemplate="{DataTemplate postlogin:Page2}" />
</ShellSection>
<ShellContent Route="page3"
Title="Page3"
Icon="Page3.png"
ContentTemplate="{DataTemplate postlogin:Page3}" />
</ShellSection>
<ShellContent Route="page4"
Title="Page4"
Icon="Pag4.png"
ContentTemplate="{DataTemplate postlogin:Page4}" />
</ShellSection>
</ShellItem>
<FlyoutItem Route="others"
Title="OTHERS"
FlyoutDisplayOptions="AsMultipleItems">
<Tab>
<ShellContent Route="cats"
Title="Cats"
Icon="next_7.png"
/>
<ShellContent Route="dogs"
Title="Dogs"
Icon="next_7.png"
/>
</Tab>
</FlyoutItem>
</Shell>
So, my problem is as follows: Once I got to for example, SignUpPage nad I click a button, and that button executes:
await Shell.Current.Navigation.PushAsync(new SentEmailPage()); it goews to catch part with an message: Object reference not set to an instance of an object.at Xamarin.Forms.ShellSection.OnPushAsync
this solved my problem
Device.InvokeOnMainThreadAsync(() =>
{
Navigation.PushAsync(new CameraPage());
});