Could not implement NavigationPageRenderer Custom renderer xamarin form - xamarin.forms

I have google a lot about building CustomRenderer to display custom navigationpage on xamarin form (to display gradient on navigationbar) but did not succeed.
here is my code:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace BillerApp
{
public class GradientNavigationBar: NavigationPage
{
public GradientNavigationBar(Page page): base(page)
{
}
public GradientNavigationBar() : base()
{
}
public static readonly BindableProperty StartColorProperty = BindableProperty.Create(
nameof(StartColor),
typeof(Color),
typeof(GradientNavigationBar),
Color.Default);
public static readonly BindableProperty EndColorProperty = BindableProperty.Create(
nameof(EndColor),
typeof(Color),
typeof(GradientNavigationBar),
Color.Default);
public Color StartColor {
get { return (Color)GetValue(StartColorProperty); }
set { SetValue(StartColorProperty, value); }
}
public Color EndColor
{
get { return (Color)GetValue(EndColorProperty); }
set { SetValue(EndColorProperty, value); }
}
}
}
and following is the renderer on Xamarin.Droid
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using BillerApp;
using Xamarin.Forms.Platform.Android;
using Android.Graphics.Drawables;
using BillerApp.Droid;
using System.ComponentModel;
[assembly: ExportRenderer(typeof(GradientNavigationBar), typeof(GrandientNavigationBarRenderer))]
namespace BillerApp.Droid
{
[Activity(Name = "com.companyname.BillerApp.MainActivity")]
public class GrandientNavigationBarRenderer: Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer
{
//public GrandientNavigationBarRenderer(Context context): base(context){} //can not use this constructor
protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
{
base.OnElementChanged(e); // I got Invalid Cast Exception if Inherit from NavigationRenderer
if (e.OldElement != null || Element == null)
{
return;
}
var p = this.Element as GradientNavigationBar;
var context = (Activity)this.Context;
var sc = new int[] { p.StartColor.ToAndroid(), p.EndColor.ToAndroid() };
var grad = new GradientDrawable(GradientDrawable.Orientation.TopBottom, sc);
var t = context.ActionBar; // here i got null
t.SetSplitBackgroundDrawable(grad);
context.ActionBar.SetBackgroundDrawable(grad);
}
}
}
this is what i am trying to achieve:
I am using VS 2015 Community edition and have updated SDK tools to date

I would do it simply by adding something like this to your layout folder:
toolbar_gradient.xml
<gradient
android:type="linear"
android:startColor="#F3A183"
android:endColor="#EC6F66"
android:angle="270"/>
</shape>
Then in your Toolbar.xml add this line of code:
android:background="#layout/toolbar_gradient"

Related

Using SQLite-net-pcl and can't update the data

So i have this really annoying problem where i Can't seem to get it to update any of the databases i have created, whats worse the i can see the instance is showing the updated information but isn't applying it. I'm really new to this and is my first course project.
This is the code that is being used to update the data:
'''
using Project.Database;
using Project.DataClasses;
using Project.Pages.SuperPages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Project.Pages.UpdateDeleteListItem
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class UpdateDeleteList : ContentPage
{
private new readonly Label Title;
private Style LabelStyle;
private StoreDetails UpdateStoreDetails;
private Entry SNum;
private Entry SName;
private Entry SMName;
private Entry Addy;
public UpdateDeleteList(string pageType, object Item)
{
InitializeComponent();
BindingContext = Item;
UpdateStoreDetails = (StoreDetails)Item;
SetLabelStyle();
string titleMsg = "Update or Delete Selected " + pageType;
Frame frame = new Frame();
Label title = new Label() {Text = titleMsg };
Title = title;
StackLayout titleStack = new StackLayout() { Children = { Title } };
frame.Content = titleStack;
if (pageType == "Store")
{
StoreUDLItem(frame);
}
if (pageType == "Ticket")
{
TicketUDLItem(frame);
}
StylePage();
}
private void SaveButton_Clicked(object sender, EventArgs args)
{
if (StoreCheckValues() == true)
{
var store = SName;
var storeManager = SMName;
var storeNumber = SNum;
var address = Addy;
var storeDataAccess = new StoreDataAccess();
UpdateStoreDetails.StoreName = store.Text;
UpdateStoreDetails.StoreManger = storeManager.Text;
UpdateStoreDetails.StoreNumber = storeNumber.Text;
UpdateStoreDetails.Address = address.Text;
//MerchandiserKey = GetMerchId()
storeDataAccess.SaveStoreDetails(UpdateStoreDetails);
storeDataAccess.SaveAllStoreDetails();
}
'''
here is the data access methods:
'''
using Project.DataClasses;
using SQLite;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using Xamarin.Forms;
namespace Project.Database
{
class StoreDataAccess
{
private SQLiteConnection database;
private static object collisionLock = new object();
public ObservableCollection<StoreDetails> StoreDetails { get; set; }
public StoreDataAccess()
{
database = DependencyService.Get<IDatabaseConnection>().DbConnectionStore();
database.CreateTable<StoreDetails>();
this.StoreDetails = new ObservableCollection<StoreDetails>(database.Table<StoreDetails>());
//AddNewTicket(new Ticket ticket);
}
//add ticket method
public void AddNewStore(StoreDetails item)
{
this.StoreDetails.Add(item);
}
//retrieve ticket method
public StoreDetails GetStoreDetails(int id)
{
lock (collisionLock)
{
return database.Table<StoreDetails>().FirstOrDefault(StoreDetails => StoreDetails.StoreId == id);
}
}
//save ticket
public int SaveStoreDetails(StoreDetails storeDetailsInstance)
{
lock (collisionLock)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
else
{
database.Insert(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
//database.Commit();
}
}
public void SaveAllStoreDetails()
{
lock (collisionLock)
{
foreach (var storeDetailsInstance in this.StoreDetails)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
}
else
{
database.Insert(storeDetailsInstance);
}
}
}
}
'''
This is the page that is sending the information to the first code block to bind the data too
'''
using Project.Database;
using Project.DataClasses;
using Project.Pages.UpdateDeleteListItem;
using SQLite;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Project.Pages.ListPages
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StoreList : ContentPage
{
private ObservableCollection<StoreDetails> Items { get; set; }
private readonly StoreDataAccess storeDataAccess;
private readonly SQLiteConnection database;
public StoreList()
{
InitializeComponent();
storeDataAccess = new StoreDataAccess();
this.BindingContext = this.storeDataAccess;
Items = storeDataAccess.StoreDetails;
StoreView.ItemsSource = Items;
}
async void Handle_ItemTapped(object sender, ItemTappedEventArgs e)
{
if (e.Item == null) { return; }
else
{
//var id = Items[e.ItemIndex].StoreId;
await Navigation.PushAsync(new UpdateDeleteList("Store", e.Item));
//Deselect Item
((ListView)sender).SelectedItem = null;
}
}
//page reload handle
protected override void OnAppearing()
{
base.OnAppearing();
var dbName = "StoreListDatabase.db3";
var path = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.Personal), dbName);
if (database == null)
{
new StoreDataAccess();
}
using (SQLiteConnection conn = new SQLiteConnection(path))
{
Items = storeDataAccess.StoreDetails;
StoreView.ItemsSource = Items;
}
}
}
}
'''
and lastly here is my databbase model for it:
'''
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using SQLite;
using System.ComponentModel;
namespace Project.DataClasses
{
class StoreDetails : INotifyPropertyChanged
{
private int _storeId;
[PrimaryKey, AutoIncrement, NotNull]
public int StoreId
{
get { return _storeId; }
set { _storeId = value; OnPropertyChanged(nameof(StoreId)); }
}
private string _storeName;
[NotNull, DefaultValue("Enter Store Name")]
public string StoreName
{
get { return _storeName; }
set { _storeName = value; OnPropertyChanged(nameof(_storeName)); }
}
private string _storeManger;
[NotNull, DefaultValue("Enter Store Managers Name")]
public string StoreManger
{
get { return _storeManger; }
set { _storeManger = value; OnPropertyChanged(nameof(StoreManger)); }
}
private string _storeNumber;
[NotNull, DefaultValue("Enter Store Number")]
public string StoreNumber
{
get { return _storeNumber; }
set { _storeNumber = value; OnPropertyChanged(nameof(StoreNumber)); }
}
private string _address;
[NotNull, DefaultValue("Enter Address")]
public string Address
{
get { return _address; }
set { _address = value; OnPropertyChanged(nameof(Address)); }
}
private int _merchandiserKey;
[NotNull]
public int MerchandiserKey
{
get { return _merchandiserKey; }
set { _merchandiserKey = value; OnPropertyChanged(nameof(MerchandiserKey)); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
'''
any help would be greatly appreciated
'''
public int SaveStoreDetails(StoreDetails storeDetailsInstance)
{
lock (collisionLock)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
else
{
database.Insert(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
//database.Commit();
}
}
'''
this is the area where it all seems to be going wrong i just don't know why
Thank You Jason, you were correct in that the error was in calling both the savefunctions and overwriting it!!

cannot relaunch the app when we use foreground service using xamarin forms

I am using xamarin forms for my app. I am using foreground service for my app to work on background. I kill the App and when I try to relaunch the App, I can't open the App. Here I am adding My service code below. Please see the code and give me suggestions to solve this issue.
My Service Code is below:
MyPrjService.cs:
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
using System.Threading;
using System.Threading.Tasks;
using Android.Support.V4.App;
using Android;
using Android.Media;
using MyPrj.Interface;
using Xamarin.Forms;
using System.IO;
using Android.Net;
using MyPrj.Common;
using MyPrj.Services;
using Android.App;
using MyPrj.BusinessLogic;
using MyPrj.Helper;
using System;
using Plugin.Connectivity;
using MyPrj.Form;
using Android.Graphics;
namespace MyPrj.Droid.Services
{
[Service]
public class MyPrjService : Service
{
CancellationTokenSource _cts;
private static ILogger logger = DependencyService.Get<ILogManager>().GetLog();
public const string LOCATION_CHANNEL = "default";
NotificationManager manager;
NotificationCompat.Builder notification;
public override void OnCreate()
{
base.OnCreate();
manager = (NotificationManager)Forms.Context.GetSystemService("notification");
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
StartLocationServiceForeground();
return StartCommandResult.Sticky;
}
void StartLocationServiceForeground()
{
try
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var chan1 = new NotificationChannel(LOCATION_CHANNEL,
new Java.Lang.String("Primary"), NotificationImportance.High);
manager.CreateNotificationChannel(chan1);
notification = new NotificationCompat.Builder(Forms.Context, LOCATION_CHANNEL);
notification.SetOngoing(true)
//.SetLargeIcon(BitmapFactory.DecodeResource(Resources, Resource.Drawable.icon))
.SetSmallIcon(Resource.Drawable.icon_transparent)
.SetContentTitle("MyPrj is running background")
.SetContentText("Tab for more information or to stop the app")
.SetColor(0x9c6114)
.SetPriority(NotificationCompat.PriorityHigh);
StartForeground(1, notification.Build());
}
}
catch(System.Exception ex)
{
}
}
public override void OnDestroy()
{
StopForeground(true);
if (manager!=null)
{
manager.CancelAll();
}
base.OnDestroy();
}
}
}
App.xaml.cs:
protected override async void OnSleep()
{
try
{
var context = Droid.MainActivity.Instance;
if (context != null)
{
context.StartServiceFromApp();
}
}
}
protected async override void OnResume()
{
var context = Droid.MainActivity.Instance;
if (context != null)
{
context.StopServiceFromApp();
}
}
MainActivity.cs:
public void StartServiceFromApp()
{
os 9
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var intent1 = new Intent(this, typeof(MyPrjService));
StartService(intent1);
}
}
public void StopServiceFromApp()
{
var intent1 = new Intent(this, typeof(ScoularService));
StopService(intent1);
}

xamarin forms mvvm pattern picker dynamically

I am using xamarin forms MVVM pattern. I am using picker and assign itemdisplaybinging and itemssource dynamically from sqlite database. I have attached images.
In AddItems.xaml:
enter code here
<Picker ItemDisplayBinding="{Binding itemlist.ItemName}"
ItemsSource="{Binding itemlist.ItemID}" Title="Select Item..."
Style="{StaticResource PickerFrameStyle}"></Picker>
In AddItems.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ERPSoftware.ViewModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ERPSoftware.Pages.Add
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AddItems : ContentPage
{
public AddItems()
{
InitializeComponent();
var vm = new AddViewModel();
this.BindingContext = vm;
}
}
}
In AddViewModel.cs(ViewModel):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using ERPSoftware.Models;
using ERPSoftware.SQLiteDatabase;
using System.Runtime.CompilerServices;
namespace ERPSoftware.ViewModel
{
public class AddViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _IsBusy;
//public ICommand AddItemCommand { protected get; set; }
public ItemPickerPageModel _ItemPickerPageModel;
UETrackDatabase uETrackDatabase = new UETrackDatabase();
private List<ItemPickerPageModel> _itemlist=new List<ItemPickerPageModel>();
public AddViewModel()
{
IsBusy = false;
ItemPickerPageModel = new ItemPickerPageModel();
var ItemList = uETrackDatabase.GetItemPicker();
if (ItemList.Count > 0)
{
foreach(var list in ItemList)
{
_itemlist.Add(new ItemPickerPageModel {ItemID=list.ItemID,ItemName=list.ItemName });
}
}
}
public List<ItemPickerPageModel> itemlist
{
get { return _itemlist; }
private set {
_itemlist = value;
OnPropertyChanged();
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I attached viewmodel screen with this. The Picker shows empty when running the project. Please help me to resolve this issue.
enter image description here
Regards,
Manthiram C
Your making a little bit confusion between the Bindings in the Picker.
<Picker ItemDisplayBinding="{Binding ItemName}"
ItemsSource="{Binding itemlist}"
Title="Select Item..."
Style="{StaticResource PickerFrameStyle}"></Picker>

Custom event not raising in EventHandler .NET CORE

Using .net core I'm implementing class library to push bulk emails into Email server.Email server will consume my email list and gives feedback after complete.this will take 20-30 seconds.When I got feedback from email server I need to fire method.
I have referred this article to implement event handler.But when I debug it
EventHandler OnFeedbackReceived
parameter is null.see image below
This is class library code.
using System;
using System.Text;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Collections.Generic;
namespace OSH_EmailServerLibrary
{
public static class EmailMQServerLibrary
{
public static event EventHandler<EmailFeedbackEventArgs> OnFeedbackReceived;
public static void PushToMQ(List<EmailMessage> _emailList)
{
//
// Long RabbitMQ msg push code here
//
EmailMessageFeedback feedback = new EmailMessageFeedback { Description = "Completed", SuccessCount = 10, FailedCount = 0 };
SendFeedback(feedback);
Console.ReadLine();
}
private static EmailMessageFeedback SendFeedback(EmailMessageFeedback feedback)
{
if (OnFeedbackReceived != null)
{
OnFeedbackReceived(feedback, new
EmailFeedbackEventArgs(feedback));
}
return feedback;
}
}
public class EmailFeedbackEventArgs : EventArgs
{
public EmailFeedbackEventArgs(EmailMessageFeedback _feedback)
{
feedback = _feedback;
}
public EmailMessageFeedback feedback { get; set; }
}
}
This is how I user it in a console application
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using OSH_EmailServerLibrary;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace EmailServerSenderSampleConsole
{
class Program
{
static void Main(string[] args)
{
List<EmailMessage> _emailList = _emails.GetAllEmailToSend();
EmailMQServerLibrary.PushToMQ(_emailList);
EmailMQServerLibrary.OnFeedbackReceived += EmailMQServerLibrary_OnFeedbackReceived;
}
private static void EmailMQServerLibrary_OnFeedbackReceived(object sender, EmailFeedbackEventArgs e)
{
}
}
}
Finally Fixed my issue.Issue was not in my class library.Issue was I did subscribe event after PushToMQ() in my console application which is wrong..Thank you so much #Hans Passant helping me out.
here is my corrected answer.I think this will help others like me.
Class Library >>
using System;
using System.Text;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Collections.Generic;
namespace OSH_EmailServerLibrary
{
public static class EmailMQServerLibrary
{
public static event EventHandler<EmailFeedbackEventArgs> OnFeedbackReceived;
public static void PushToMQ(List<EmailMessage> _emailList)
{
//
// Long RabbitMQ msg push code here
//
EmailMessageFeedback feedback = new EmailMessageFeedback { Description = "Completed", SuccessCount = 10, FailedCount = 0 };
SendFeedback(feedback);
Console.ReadLine();
}
private static EmailMessageFeedback SendFeedback(EmailMessageFeedback feedback)
{
if (OnFeedbackReceived != null)
{
OnFeedbackReceived(feedback, new
EmailFeedbackEventArgs(feedback));
}
return feedback;
}
}
public class EmailFeedbackEventArgs : EventArgs
{
public EmailFeedbackEventArgs(EmailMessageFeedback _feedback)
{
feedback = _feedback;
}
public EmailMessageFeedback feedback { get; set; }
}
}
Console Application >>
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using OSH_EmailServerLibrary;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace EmailServerSenderSampleConsole
{
class Program
{
static void Main(string[] args)
{
List<EmailMessage> _emailList = _emails.GetAllEmailToSend();
EmailMQServerLibrary.OnFeedbackReceived +=
EmailMQServerLibrary_OnFeedbackReceived; //-- worked
EmailMQServerLibrary.PushToMQ(_emailList);
//EmailMQServerLibrary.OnFeedbackReceived +=
EmailMQServerLibrary_OnFeedbackReceived; -- Not working like this
}
private static void EmailMQServerLibrary_OnFeedbackReceived(object sender, EmailFeedbackEventArgs e)
{
}
}
}

xamarin forms Tabbed page title no wrap

i have tabbed page with number of pages , the issue here that the title of the page is not appearing well, it need to be no wrap or expand to fit the text.
any suggestion to solve this issue.
You Need to create one TabbedPageRenderer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android.AppCompat;
using AppTab.Droid;
using Android.Support.V4.View;
using Android.Support.Design.Widget;
using System.ComponentModel;
using Xamarin.Forms.Platform.Android;
using AppTab;
using Android.Graphics.Drawables;
using Android.Graphics;
[assembly: ExportRenderer(typeof(CustomTabbedPage), typeof(ScrollableTabbedPage))]
namespace AppTab.Droid
{
public class ScrollableTabbedPage : TabbedPageRenderer
{
public override void OnViewAdded(Android.Views.View child)
{
base.OnViewAdded(child);
var tabLayout = child as TabLayout;
if (tabLayout != null)
{
tabLayout.TabMode = TabLayout.ModeScrollable;
}
}
public static void Init()
{
var unused = DateTime.UtcNow;
}
private CustomTabbedPage FormsTabbedPage => Element as CustomTabbedPage;
private Android.Graphics.Color _selectedColor = Android.Graphics.Color.Black;
private static readonly Android.Graphics.Color DefaultUnselectedColor = Xamarin.Forms.Color.Gray.ToAndroid();
private static Android.Graphics.Color _barBackgroundDefault;
private Android.Graphics.Color _unselectedColor = DefaultUnselectedColor;
ViewPager _viewPager;
TabLayout _tabLayout;
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
// Get tabs
for (var i = 0; i < ChildCount; i++)
{
var v = GetChildAt(i);
var pager = v as ViewPager;
if (pager != null)
_viewPager = pager;
else if (v is TabLayout)
_tabLayout = (TabLayout)v;
}
if (e.OldElement != null)
{
_tabLayout.TabSelected -= TabLayout_TabSelected;
_tabLayout.TabUnselected -= TabLayout_TabUnselected;
}
if (e.NewElement != null)
{
_barBackgroundDefault = (_tabLayout.Background as ColorDrawable)?.Color ??
Android.Graphics.Color.Blue;
SetSelectedColor();
SetBarBackgroundColor();
_tabLayout.TabSelected += TabLayout_TabSelected;
_tabLayout.TabUnselected += TabLayout_TabUnselected;
SetupTabColors();
SelectTab(0);
}
}
void SelectTab(int position)
{
if (_tabLayout.TabCount > position)
{
_tabLayout.GetTabAt(position).Icon?
.SetColorFilter(_selectedColor, PorterDuff.Mode.SrcIn);
_tabLayout.GetTabAt(position).Select();
}
else
{
throw new IndexOutOfRangeException();
}
}
void SetupTabColors()
{
_tabLayout.SetSelectedTabIndicatorColor(_selectedColor);
_tabLayout.SetTabTextColors(_unselectedColor, _selectedColor);
for (int i = 0; i < _tabLayout.TabCount; i++)
{
var tab = _tabLayout.GetTabAt(i);
tab.Icon?.SetColorFilter(_unselectedColor, PorterDuff.Mode.SrcIn);
}
}
private void TabLayout_TabUnselected(object sender, TabLayout.TabUnselectedEventArgs e)
{
var tab = e.Tab;
tab.Icon?.SetColorFilter(_unselectedColor, PorterDuff.Mode.SrcIn);
}
private void TabLayout_TabSelected(object sender, TabLayout.TabSelectedEventArgs e)
{
var tab = e.Tab;
_viewPager.CurrentItem = tab.Position;
tab.Icon?.SetColorFilter(_selectedColor, PorterDuff.Mode.SrcIn);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
int lastPosition = _tabLayout.SelectedTabPosition;
switch (e.PropertyName)
{
case nameof(CustomTabbedPage.BarBackgroundColor):
case nameof(CustomTabbedPage.BarBackgroundApplyTo):
SetBarBackgroundColor();
SetupTabColors();
SelectTab(lastPosition);
break;
case nameof(CustomTabbedPage.SelectedColor):
SetSelectedColor();
SetupTabColors();
SelectTab(lastPosition);
break;
default:
base.OnElementPropertyChanged(sender, e);
break;
}
}
private void SetSelectedColor()
{
if (FormsTabbedPage.SelectedColor != default(Xamarin.Forms.Color))
_selectedColor = FormsTabbedPage.SelectedColor.ToAndroid();
}
private void SetBarBackgroundColor()
{
if (FormsTabbedPage.BarBackgroundApplyTo.HasFlag(BarBackgroundApplyTo.Android))
{
_tabLayout.SetBackgroundColor(FormsTabbedPage.BarBackgroundColor.ToAndroid());
_unselectedColor = FormsTabbedPage.BarBackgroundColor != default(Xamarin.Forms.Color)
? FormsTabbedPage.BarBackgroundColor.ToAndroid()
: DefaultUnselectedColor;
}
else
{
_tabLayout.SetBackgroundColor(_barBackgroundDefault);
_unselectedColor = DefaultUnselectedColor;
}
}
}
}
Second you Need CustomTabbedPage class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace AppTab
{
[Flags]
public enum BarBackgroundApplyTo
{
None = 0x01,
Android = 0x10,
iOS = 0x100
}
public class CustomTabbedPage : TabbedPage
{
public CustomTabbedPage()
{
}
public static readonly BindableProperty SelectedColorProperty =
BindableProperty.Create(nameof(SelectedColor), typeof(Color), typeof(CustomTabbedPage), default(Color));
public Color SelectedColor
{
get => (Color)GetValue(SelectedColorProperty);
set => SetValue(SelectedColorProperty, value);
}
public static readonly BindableProperty BarBackgroundApplyToProperty =
BindableProperty.Create(nameof(BarBackgroundApplyTo), typeof(BarBackgroundApplyTo), typeof(CustomTabbedPage), BarBackgroundApplyTo.Android);
public BarBackgroundApplyTo BarBackgroundApplyTo
{
get => (BarBackgroundApplyTo)GetValue(BarBackgroundApplyToProperty);
set => SetValue(BarBackgroundApplyToProperty, value);
}
public new static readonly BindableProperty BarBackgroundColorProperty =
BindableProperty.Create(nameof(BarBackgroundColor), typeof(Color), typeof(CustomTabbedPage), default(Color));
public new Color BarBackgroundColor
{
get => (Color)GetValue(BarBackgroundColorProperty);
set => SetValue(BarBackgroundColorProperty, value);
}
}
}
And Third You Need CustomMain Page
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace AppTab
{
public class CustomMain : CustomTabbedPage
{
public CustomMain()
{
BarBackgroundApplyTo = BarBackgroundApplyTo.Android;
//BarBackgroundColor = Color.Red;
Children.Add(new abc() { Title = "ABC"});
Children.Add(new xyz() { Title = "XYZ" });
Children.Add(new pqr() { Title = "PQR" });
Children.Add(new str() { Title = "STR" });
Children.Add(new ftx() { Title = "FTX" });
Children.Add(new dtb() { Title = "DTB" });
}
}
}
Click here for ScreenShot
In Resources->Layout->Tabbar.xml set tabMode to "scrollable".
It should work.

Resources