underline when writing text in entry view - xamarin,forms android - android

When I write text in entry view in xamarin.forms I alway have underline under the text
I search all the web for a solution - it was to change the background to null or transparent BUT its not working.
is there any other solution ?

I know this is an old question but it seems to get viewed/asked a lot, and Xamarin still hasn't added built-in support for customizing this very basic UI feature, so I will post an answer here that will hopefully be helpful. Also most answers you will find online (including the Microsoft documentation) show you how to create a static custom renderer, but what we really want is a control where we can set properties in shared code like with any other control. I figured out how to do this so I will share here. I've also included a property for setting border color and width since this is a common UI element we like to set.
In your shared project create a class called CustomEntry (you can rename this later if you wish).
using Xamarin.Forms;
namespace CustomizedControl
{
public class CustomEntry : Entry
{
public Color BorderColor { get; set; }
public int BorderThickness { get; set; }
public bool HasUnderline { get; set; }
}
}
In your Android project create a class called CustomEntryAndroid and paste in this code:
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using CustomizedControl;
using CustomizedControl.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryAndroid))]
namespace CustomizedControl.Droid
{
public class CustomEntryAndroid : EntryRenderer
{
public CustomEntryAndroid(Context context) : base(context)
{ }
private bool HasUnderline;
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var element = (CustomEntry)Element;
HasUnderline = element.HasUnderline;
var BorderClr = element.BorderColor.ToAndroid();
if (HasUnderline == false)
{
GradientDrawable gd = new GradientDrawable();
gd.SetColor(Android.Graphics.Color.Transparent);
Control.SetBackgroundDrawable(gd); //this is depreciated but it doesn't matter, the new method SetBackgroud simply calls SetBackgroundDrawable
} //Else maintain default underline
if (BorderClr != Android.Graphics.Color.Transparent)
{
int borderThickness = element.BorderThickness;
if (borderThickness == 0) { borderThickness = 1; } //in case border thickness was not set then default to 1
var brdr = new ShapeDrawable(new Android.Graphics.Drawables.Shapes.RectShape());
brdr.Paint.Color = BorderClr;
brdr.Paint.SetStyle(Paint.Style.Stroke);
Control.Background = brdr;
GradientDrawable gd = new GradientDrawable();
gd.SetColor(Android.Graphics.Color.Transparent);
gd.SetStroke(borderThickness, BorderClr);
Control.SetBackground(gd);
}
}//end if
}//end OnElementChanged
}//end public class CustomEntryAndroid
}//end NameSpace
You can now use the custom entry in any xaml page and get rid of the underline like this:
<local:CustomEntry HasUnderline="False" />
Here is a very simple content page with pretty much nothing on it but an entry:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:CustomizedControl"
x:Class="CustomizedControl.MainPage">
<StackLayout Padding="30">
<local:CustomEntry Text="Test text" WidthRequest="250" HorizontalOptions="Start" HasUnderline="False" />
</StackLayout>
</ContentPage>
Note the import statement xmlns:local="clr-namespace:CustomizedControl". Here is the output:
Now with the underline attribute set to true:
<local:CustomEntry Text="Test text" WidthRequest="250" HorizontalOptions="Start" HasUnderline="True" />
And finally with a border:
<local:CustomEntry Text="Test text" WidthRequest="250" HorizontalOptions="Start" BorderColor="Purple" />
Notice I did not specify a width in the xaml but the border still appeared. This is because I set the default width to 1 in the Android custom renderer. But you can set the width thicker like this BorderThickness="6" or modify the default behavior if you wanted to.
One final note: the namespace I used for this project is "CustomizedControl", so you will of course need to replace "CustomizedControl" with whatever your namespace is.

Take a look here
http://geeks.ms/xamarinteam/2015/04/20/branding-a-xamarin-forms-app-on-android-accent-color/
Your ask was a little obscure, but I think the link above can help you ... you just need to set the underline color for all status as same to the background or transparent.
in Android 5.0 devices, which use the specified accent color you can just change the color, another hand, in androids 4.< you need to create an image

Related

Nativescript transparent actionbar

I have searched StackOverflow see here: https://stackoverflow.com/search?q=nativescript+transparent+actionbar but all the comments seem to be aimed at Nativescript IOS transparent Actionabar. I do not want to create a custom Actionabar I know I can do that; I just want to know how to make the stock Actionbar transparent but still make the text viewable.
Try this, I originally wrote this on Angular but it can work with any flavor you will need to adjust the syntax accordingly.
HTML
<ActionBar title="Home" class="action-bar" android:backgroundColor="transparent" (loaded)="onActionBarLoaded($event)" (layoutChanged)="onLayoutChanged($event)">
</ActionBar>
<StackLayout class="page" (loaded)="onLoaded($event)" [paddingTop]="fromTop">
<Label class="h2" text="Hello!"></Label>
</StackLayout>
TS
fromTop: number = 0;
onLoaded(event: EventData) {
const layout = <GridLayout>event.object,
page = layout.page;
if (page.android) {
page.android.removeRowAt(0);
}
}
onActionBarLoaded(event: EventData) {
const actionBar = <ActionBar>event.object;
if (actionBar.ios) {
(<any>actionBar).updateFlatness = function (navBar) {
actionBar.ios.setBackgroundImageForBarMetrics(UIImage.new(), UIBarMetrics.Default);
actionBar.ios.translucent = true;
};
}
}
onLayoutChanged(event: EventData) {
const actionBar = <ActionBar>event.object;
if (actionBar.android) {
this.fromTop = layout.toDeviceIndependentPixels(actionBar.getMeasuredHeight());
}
}
Use Core event binding syntax - for example (loaded)="onLoaded($event)" will become loaded="{{ onLoaded }}" and you will define the callback in view model. Similarly for property binding, define fromTop in View Model and bind it in XML.
Playground Sample

Using Xamarin Forms for Android and IOS, how to display a status indicator for 4 unique states

For Xamarin Forms for Android and IOS, how do I display a status indicator (not an activity indicator) showing up to 4 unique states of the server, data or other objects, all set in the code behind with binded objects/strings/ints?
Skia sharp and RoundedBoxView are two libraries that I've found, however they're significantly more complex to implement that I was hoping for.
Essentially what I'm looking for is to display one of the following in a grid:
Error (Red)
Warning (Yellow)
No problems (Green)
Other/TBD (Grey)
Thank you for your time and assistance. The answer MUST be in Xamarin.Forms instead of native platform specific. I also greatly prefer something that already exists in Xamarin.Forms instead of getting another library and implementing it but not opposed to it.
how do I display a status indicator (not an activity indicator) showing up to 4 unique states of the server, data or other objects, all set in the code behind with binded objects/strings/ints?
But is there a way to disable the animation and fill it so its solid.
If just want to display a Solid circle, then the BoxView can also do it and change the color.
Set CornerRadius property of BoxView can show as a circle .
Just binding Color property of BoxView to ViewModel,and converting the value of Color by IValueConverter.
If want color dynamic changed, also need to use INotifyPropertyChanged in ViewModel.
Xmal file:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:PickerCase="clr-namespace:PickerCase" //PickerCase is project namespace
x:Class="PickerCase.NextPage"> //NextPage is current page name
<ContentPage.Resources>
<ResourceDictionary>
<PickerCase:StringToColorConverter x:Key="StringToColorConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<BoxView Color="{Binding MyColor, Converter={StaticResource StringToColorConverter}}"
HorizontalOptions="Center"
WidthRequest="40"
HeightRequest="40"
CornerRadius="20"/>
</StackLayout>
</ContentPage.Content>
Creating a StringToColorConverter.cs file to convert color by string value:
public class StringToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//throw new NotImplementedException();
string valueAsString = value.ToString();
switch (valueAsString)
{
case ("Red"):
{
return Color.Red;
}
case ("Yellow"):
{
return Color.Yellow;
}
case ("Green"):
{
return Color.Green;
}
case ("Gray"):
{
return Color.Gray;
}
default:
{
return Color.FromHex(value.ToString());
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//throw new NotImplementedException();
return null;
}
}
ViewModel add MyColor property ,and OnPropertyChanged it.
class SecondDataModel : INotifyPropertyChanged
{
private string mycolor = "Gray"; //Default color is Gray
public string MyColor
{
set
{
if (mycolor != value)
{
mycolor = value;
OnPropertyChanged("MyColor");
}
}
get
{
return mycolor;
}
}
public SecondDataModel()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Finally in ContentPage bind this ViewModel:
SecondDataModel secondDataModel;
...
secondDataModel = new SecondDataModel();
BindingContext = secondDataModel;
When the data from API Server, you can change color as follow:
secondDataModel.MyColor = "Red";
...
secondDataModel.MyColor = "Yelow";
...
secondDataModel.MyColor = "Green";
An alternative/slightly different implementation to Junior Jiang's solution is to have a Converter which converts to an Image rather than converting colours. You can then have a different Image asset for each status.
Note using an ActivityIndicator would be horrible! The implementation on different platforms is different, and would just not look right.

Xamarin.Forms ListView: Set the highlight color of a tapped item

Using Xamarin.Forms, how can I define the highlight/background color of a selected/tapped ListView item?
(My list has a black background and white text color, so the default highlight color on iOS is too bright. In contrast, on Android there is no highlighting at all - up to a subtle horizontal gray line.)
Example: (left: iOS, right: Android; while pressing "Barn2")
In Android simply edit your styles.xml file under Resources\values adding this:
<resources>
<style name="MyTheme" parent="android:style/Theme.Material.Light.DarkActionBar">
<item name="android:colorPressedHighlight">#color/ListViewSelected</item>
<item name="android:colorLongPressedHighlight">#color/ListViewHighlighted</item>
<item name="android:colorFocusedHighlight">#color/ListViewSelected</item>
<item name="android:colorActivatedHighlight">#color/ListViewSelected</item>
<item name="android:activatedBackgroundIndicator">#color/ListViewSelected</item>
</style>
<color name="ListViewSelected">#96BCE3</color>
<color name="ListViewHighlighted">#E39696</color>
</resources>
It looks like there is actually a cross-platform way to do this that works on both iOS and Android (not sure about Windows). It uses only binding and does not require custom renderers (which seems rare). This is a mash-up of lots of googling, so thanks to anyone who I may have borrowed from...
I am assuming ViewCells, but this should work for Text or Image cells as well. I am only including the relevant code here beyond the typical text, image, etc.
On your page do something like this:
MyModel model1 = new MyModel();
MyModel model2 = new MyModel();
ListView list = new ListView
{
ItemsSource = new List<MyModel> { model1, model2 };
ItemTemplate = new DataTemplate( typeof(MyCell) )
};
Your custom Model might look something like this:
public class MyModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Color _backgroundColor;
public Color BackgroundColor
{
get { return _backgroundColor; }
set
{
_backgroundColor = value;
if ( PropertyChanged != null )
{
PropertyChanged( this, new PropertyChangedEventArgs( "BackgroundColor" ) );
}
}
}
public void SetColors( bool isSelected )
{
if ( isSelected )
{
BackgroundColor = Color.FromRgb( 0.20, 0.20, 1.0 );
}
else
{
BackgroundColor = Color.FromRgb( 0.95, 0.95, 0.95 );
}
}
}
Then for your ItemTemplate you need a custom cell class something like this:
public class MyCell : ViewCell
{
public MyCell() : base()
{
RelativeLayout layout = new RelativeLayout();
layout.SetBinding( Layout.BackgroundColorProperty, new Binding( "BackgroundColor" ) );
View = layout;
}
}
Then in your ItemSelected event handler, do the following. Note that 'selected' is an instance of MyModel used to track the currently selected item. I am only showing background color here, but I also use this technique to reverse highlight the text and detail text colors.
private void ItemSelected( object sender, ItemTappedEventArgs args )
{
// Deselect previous
if ( selected != null )
{
selected.SetColors( false );
}
// Select new
selected = (list.SelectedItem as MyModel);
selected.SetColors( true );
}
iOS
Solution:
Within a custom ViewCellRenderer you can set the SelectedBackgroundView. Simply create a new UIView with a background color of your choice and you're set.
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var cell = base.GetCell(item, reusableCell, tv);
cell.SelectedBackgroundView = new UIView {
BackgroundColor = UIColor.DarkGray,
};
return cell;
}
Result:
Note:
With Xamarin.Forms it seems to be important to create a new UIView rather than just setting the background color of the current one.
Android
Solution:
The solution I found on Android is a bit more complicated:
Create a new drawable ViewCellBackground.xml within the Resources>drawable folder:
<?xml version="1.0" encoding="UTF-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" >
<shape android:shape="rectangle">
<solid android:color="#333333" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#000000" />
</shape>
</item>
</selector>
It defines solid shapes with different colors for the default state and the "pressed" state of a UI element.
Use a inherited class for the View of your ViewCell, e.g.:
public class TouchableStackLayout: StackLayout
{
}
Implement a custom renderer for this class setting the background resource:
public class ElementRenderer: VisualElementRenderer<Xamarin.Forms.View>
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
SetBackgroundResource(Resource.Drawable.ViewCellBackground);
base.OnElementChanged(e);
}
}
Result:
To change color of selected ViewCell, there is a simple process without using custom renderer. Make Tapped event of your ViewCell as below
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Tapped="ViewCell_Tapped">
<Label Text="{Binding StudentName}" TextColor="Black" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
In your ContentPage or .cs file, implement the event
private void ViewCell_Tapped(object sender, System.EventArgs e)
{
if(lastCell!=null)
lastCell.View.BackgroundColor = Color.Transparent;
var viewCell = (ViewCell)sender;
if (viewCell.View != null)
{
viewCell.View.BackgroundColor = Color.Red;
lastCell = viewCell;
}
}
Declare lastCell at the top of your ContentPage like this ViewCell lastCell;
Only for Android
Add in your custom theme or your default theme under ProjectName.Android/Resources/values/styles.xml
<item name="android:colorActivatedHighlight">#android:color/transparent</item>
I have a similar process, completely cross platform, however I track the selection status myself and I have done this in XAML.
<ListView x:Name="ListView" ItemsSource="{Binding ListSource}" RowHeight="50">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<ContentView Padding="10" BackgroundColor="{Binding BackgroundColor}">
<Label Text="{Binding Name}" HorizontalOptions="Center" TextColor="White" />
</ContentView>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then in the ItemTapped Event
ListView.ItemTapped += async (s, e) =>
{
var list = ListSource;
var listItem = list.First(c => c.Id == ((ListItem)e.Item).Id);
listItem.Selected = !listItem.Selected;
SelectListSource = list;
ListView.SelectedItem = null;
};
As you can see I just set the ListView.SelectedItem to null to remove any of the platform specific selection styles that come into play.
In my model I have
private Boolean _selected;
public Boolean Selected
{
get => _selected;
set
{
_selected = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("BackgroundColor"));
}
}
public Color BackgroundColor
{
get => Selected ? Color.Black : Color.Blue;
}
I had this same issue and I solved it as well by creating a custom renderer for iOS as Falko suggests, however, I avoided the styles modification for Android, I figured out a way to use a custom renderer for Android as well.
It is kind of funky how the selected flag is always false for the android view cell that's why I had to create a new private property to track it. but other than that I think this follows a more appropriate pattern if you want to use custom renderers for both platforms, In my case I did it for TextCell but I believe it applies the same way for other CellViews.
Xamarin Forms
using Xamarin.Forms;
public class CustomTextCell : TextCell
{
/// <summary>
/// The SelectedBackgroundColor property.
/// </summary>
public static readonly BindableProperty SelectedBackgroundColorProperty =
BindableProperty.Create("SelectedBackgroundColor", typeof(Color), typeof(CustomTextCell), Color.Default);
/// <summary>
/// Gets or sets the SelectedBackgroundColor.
/// </summary>
public Color SelectedBackgroundColor
{
get { return (Color)GetValue(SelectedBackgroundColorProperty); }
set { SetValue(SelectedBackgroundColorProperty, value); }
}
}
iOS
public class CustomTextCellRenderer : TextCellRenderer
{
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var cell = base.GetCell(item, reusableCell, tv);
var view = item as CustomTextCell;
cell.SelectedBackgroundView = new UIView
{
BackgroundColor = view.SelectedBackgroundColor.ToUIColor(),
};
return cell;
}
}
Android
public class CustomTextCellRenderer : TextCellRenderer
{
private Android.Views.View cellCore;
private Drawable unselectedBackground;
private bool selected;
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, ViewGroup parent, Context context)
{
cellCore = base.GetCellCore(item, convertView, parent, context);
// Save original background to rollback to it when not selected,
// We assume that no cells will be selected on creation.
selected = false;
unselectedBackground = cellCore.Background;
return cellCore;
}
protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.OnCellPropertyChanged(sender, args);
if (args.PropertyName == "IsSelected")
{
// I had to create a property to track the selection because cellCore.Selected is always false.
// Toggle selection
selected = !selected;
if (selected)
{
var customTextCell = sender as CustomTextCell;
cellCore.SetBackgroundColor(customTextCell.SelectedBackgroundColor.ToAndroid());
}
else
{
cellCore.SetBackground(unselectedBackground);
}
}
}
}
...then, in the .xaml page, you need to add an XMLNS reference back to the new CustomViewCell...
xmlns:customuicontrols="clr-namespace:MyMobileApp.CustomUIControls"
And don't forget to make actual use of the new Custom comtrol in your XAML.
Here is the purely cross platform and neat way:
1) Define a trigger action
namespace CustomTriggers {
public class DeselectListViewItemAction:TriggerAction<ListView> {
protected override void Invoke(ListView sender) {
sender.SelectedItem = null;
}
}
}
2) Apply the above class instance as an EventTrigger action in XAML as below
<ListView x:Name="YourListView" ItemsSource="{Binding ViewModelItems}">
<ListView.Triggers>
<EventTrigger Event="ItemSelected">
<customTriggers:DeselectListViewItemAction></customTriggers:DeselectListViewItemAction>
</EventTrigger>
</ListView.Triggers>
</ListView>
Don't forget to add xmlns:customTriggers="clr-namespace:CustomTriggers;assembly=ProjectAssembly"
Note: Because none of your items are in selected mode, selection styling will not get applied on either of the platforms.
I have & use a solution similar to #adam-pedley.
No custom renderers, in xaml i bind background ViewCell Property
<ListView x:Name="placesListView" Grid.Row="2" Grid.ColumnSpan="3" ItemsSource="{Binding PlacesCollection}" SelectedItem="{Binding PlaceItemSelected}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="{Binding IsSelected,Converter={StaticResource boolToColor}}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="1" Grid.ColumnSpan="2" Text="{Binding DisplayName}" Style="{StaticResource blubeLabelBlackItalic}" FontSize="Default" HorizontalOptions="Start" />
<Label Grid.Row="2" Grid.ColumnSpan="2" Text="{Binding DisplayDetail}" Style="{StaticResource blubeLabelGrayItalic}" FontSize="Small" HorizontalOptions="Start"/>
<!--
<Label Grid.RowSpan="2" Grid.ColumnSpan="2" Text="{Binding KmDistance}" Style="{StaticResource blubeLabelGrayItalic}" FontSize="Default" HorizontalOptions="End" VerticalOptions="Center"/>
-->
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In code (MVVM) i save the lastitemselected by a boolToColor Converter i update background color
public class BoolToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Color.Yellow : Color.White;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (Color)value == Color.Yellow ? true : false;
}
}
PlaceItem LastItemSelected;
PlaceItem placeItemSelected;
public PlaceItem PlaceItemSelected
{
get
{
return placeItemSelected;
}
set
{
if (LastItemSelected != null)
LastItemSelected.IsSelected = false;
placeItemSelected = value;
if (placeItemSelected != null)
{
placeItemSelected.IsSelected = true;
LastItemSelected = placeItemSelected;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PlaceItemSelected)));
}
}
My example is extracted by a listview of places which are in a Xamarin Forms Maps (same contentpage).
I hope this solution will be usefull for somebody
In order to set the color of highlighted item you need to set the color of cell.SelectionStyle in iOS.
This example is to set the color of tapped item to transparent.
If you want you can change it with other colors from UITableViewCellSelectionStyle. This is to be written in the platform project of iOS by creating a new Custom ListView renderer in your Forms project.
public class CustomListViewRenderer : ListViewRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Control == null)
{
return;
}
if (e.PropertyName == "ItemsSource")
{
foreach (var cell in Control.VisibleCells)
{
cell.SelectionStyle = UITableViewCellSelectionStyle.None;
}
}
}
}
For android you can add this style in your values/styles.xml
<style name="ListViewStyle.Light" parent="android:style/Widget.ListView">
<item name="android:listSelector">#android:color/transparent</item>
<item name="android:cacheColorHint">#android:color/transparent</item>
</style>
This solution works fine, but if you change the caching strategy of the ListView away from the default value it stops working. It works if you new up your ListView like this:
listView = new ListView() { ... };
But if you do this it does not work (the background stays grey for the selected item):
listView = new ListView(cachingStrategy:ListViewCachingStrategy.RecycleElement) { ... };
Below is a solution that works even with a non-standard cachingStrategy. I prefer this to other solutions like having code in the OnItemSelected method coupled with a binding from the ViewModel for the background color.
Credit to #Lang_tu_bi_dien who posted the idea here: Listview Selected Item Background Color
The final code then looks like this:
Xamarin.Forms code:
namespace MyProject
{
public class ListView2 : ListView
{
public ListView2(ListViewCachingStrategy cachingStrategy) : base(cachingStrategy)
{
}
}
}
XAML on your page:
<ListView2 x:Name="myListView" ListViewCachingStrategy="RecycleElement" ItemsSource="{Binding ListSource}" RowHeight="50">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Label Text="{Binding Name}" HorizontalOptions="Center" TextColor="White" />
</ContentView>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView2>
iOS-specific renderer:
[assembly: ExportRenderer(typeof(ListView2), typeof(ListView2Renderer))]
namespace MyProject.iOS
{
public partial class ListView2Renderer : ListViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (Control != null && e != null)
{
//oldDelegate = (UITableViewSource)Control.Delegate;
Control.Delegate = new ListView2Delegate(e.NewElement);
}
}
}
class ListView2Delegate : UITableViewDelegate
{
private ListView _listView;
internal ListView2Delegate(ListView listView)
{
_listView = listView;
}
public override void WillDisplay(UITableView tableView, UITableViewCell cell, Foundation.NSIndexPath indexPath)
{
cell.SelectedBackgroundView = new UIView()
{
BackgroundColor = Color.Red.ToUIColor()
};
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_listView = null;
}
base.Dispose(disposing);
}
}
}
Note: you may run into some issues due to the fact that you are replacing the default delegate, for more info on this see Setting delegate of control in custom renderer results in lost functionality. In my project it all works as it should if I do this:
Use the normal ListView together with the ListItemViewCellRenderer code given in in the earlier posts on this thread for ListViews that use the default caching strategy ListViewCachingStrategy.RetainElement.
Use this ListView2 together for ListViews that use a non-default caching strategy i.e. ListViewCachingStrategy.RecycleElement or ListViewCachingStrategy.RecycleElementAndDataTemplate.
I am also filing a feature request with Xamarin, please upvote it if you feel this should be added to the standard ListView: ListView desperately needs a SelectedItemBackgroundColor property
Found this lovely option using effects here.
iOS:
[assembly: ResolutionGroupName("MyEffects")]
[assembly: ExportEffect(typeof(ListViewHighlightEffect), nameof(ListViewHighlightEffect))]
namespace Effects.iOS.Effects
{
public class ListViewHighlightEffect : PlatformEffect
{
protected override void OnAttached()
{
var listView = (UIKit.UITableView)Control;
listView.AllowsSelection = false;
}
protected override void OnDetached()
{
}
}
}
Android:
[assembly: ResolutionGroupName("MyEffects")]
[assembly: ExportEffect(typeof(ListViewHighlightEffect), nameof(ListViewHighlightEffect))]
namespace Effects.Droid.Effects
{
public class ListViewHighlightEffect : PlatformEffect
{
protected override void OnAttached()
{
var listView = (Android.Widget.ListView)Control;
listView.ChoiceMode = ChoiceMode.None;
}
protected override void OnDetached()
{
}
}
}
Forms:
ListView_Demo.Effects.Add(Effect.Resolve($"MyEffects.ListViewHighlightEffect"));
The easiest way to accomplish this on android is by adding the following code to your custom style :
#android:color/transparent
The previous answers either suggest custom renderers or require you to keep track of the selected item either in your data objects or otherwise. This isn't really required, there is a way to link to the functioning of the ListView in a platform agnostic way. This can then be used to change the selected item in any way required. Colors can be modified, different parts of the cell shown or hidden depending on the selected state.
Let's add an IsSelected property to our ViewCell. There is no need to add it to the data object; the listview selects the cell, not the bound data.
public partial class SelectableCell : ViewCell {
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(SelectableCell), false, propertyChanged: OnIsSelectedPropertyChanged);
public bool IsSelected {
get => (bool)GetValue(IsSelectedProperty);
set => SetValue(IsSelectedProperty, value);
}
// You can omit this if you only want to use IsSelected via binding in XAML
private static void OnIsSelectedPropertyChanged(BindableObject bindable, object oldValue, object newValue) {
var cell = ((SelectableCell)bindable);
// change color, visibility, whatever depending on (bool)newValue
}
// ...
}
To create the missing link between the cells and the selection in the list view, we need a converter (the original idea came from the Xamarin Forum):
public class IsSelectedConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
value != null && value == ((ViewCell)parameter).View.BindingContext;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotImplementedException();
}
We connect the two using this converter:
<ListView x:Name="ListViewName">
<ListView.ItemTemplate>
<DataTemplate>
<local:SelectableCell x:Name="ListViewCell"
IsSelected="{Binding SelectedItem, Source={x:Reference ListViewName}, Converter={StaticResource IsSelectedConverter}, ConverterParameter={x:Reference ListViewCell}}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This relatively complex binding serves to check which actual item is currently selected. It compares the SelectedItem property of the list view to the BindingContext of the view in the cell. That binding context is the data object we actually bind to. In other words, it checks whether the data object pointed to by SelectedItem is actually the data object in the cell. If they are the same, we have the selected cell. We bind this into to the IsSelected property which can then be used in XAML or code behind to see if the view cell is in the selected state.
There is just one caveat: if you want to set a default selected item when your page displays, you need to be a bit clever. Unfortunately, Xamarin Forms has no page Displayed event, we only have Appearing and this is too early for setting the default: the binding won't be executed then. So, use a little delay:
protected override async void OnAppearing() {
base.OnAppearing();
Device.BeginInvokeOnMainThread(async () => {
await Task.Delay(100);
ListViewName.SelectedItem = ...;
});
}
The easiest way to change the selection color is adding these to your Android.Resources.values.styles
<item name="android:colorPressedHighlight">#android:color/holo_blue_bright</item>
<item name="android:colorFocusedHighlight">#android:color/holo_blue_bright</item>
<item name="android:colorActivatedHighlight">#android:color/holo_blue_bright</item>

Android : Crouton lib and custom font

I use custom fonts in my app so i want a custom font for Crouton. I 've tried to do it with setTextAppearance, it doesn't work.
<?xml version="1.0" encoding="utf-8"?>
<com.ecab.ui.custom.TextViewCustomFont
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.crouton"
android:id="#+id/crouton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/ban_confirmation"
android:gravity="center"
android:text="TEST"
android:textColor="#android:color/white"
custom:typeface="gothamBold" />
In Style class :
INFOCUSTOM = new Builder().setDuration(3000).setTextAppearance(R.id.crouton).build();
Then, I've tried to do it by changing setTypeface() with my font, it doesn't work.
In Crouton class :
private TextView initializeTextView(final Resources resources) {
TextView text = new TextView(this.activity);
text.setId(TEXT_ID);
text.setText(this.text);
text.setTypeface(MyFonts.getGothamBookBold(this.activity));
Log.d(Constants.D_TAG, "chaneg the typeFace");
text.setGravity(this.style.gravity);
// set the text color if set
if (this.style.textColorResourceId != 0) {
text.setTextColor(resources.getColor(this.style.textColorResourceId));
}
// Set the text size. If the user has set a text size and text
// appearance, the text size in the text appearance
// will override this.
if (this.style.textSize != 0) {
text.setTextSize(TypedValue.COMPLEX_UNIT_SP, this.style.textSize);
}
// Setup the shadow if requested
if (this.style.textShadowColorResId != 0) {
initializeTextViewShadow(resources, text);
}
// Set the text appearance
if (this.style.textAppearanceResId != 0) {
text.setTextAppearance(this.activity, this.style.textAppearanceResId);
}
return text;
}
What can i do to have a custom Font ?
ps : library version ==> 1.7
Okay, I found the problem !
It works with the second solution by changing the Typeface. I had just forget to remove the
setTextAppearance(R.id.crouton)
in the Style class. So my custom style is like this :
INFOCUSTOM = new Builder().setDuration(3000).setBackgroundDrawable(R.drawable.ban_confirmation).setHeight(LayoutParams.WRAP_CONTENT)
.build();
One problem resolves, another arrives :) ! With the background drawable, the text is not vertically center
You can a custom Style that uses the resourceId of your text
appearance via Style.Builder.setTextAppearance(...).
This takes a reference from your styles.xml and uses it within the
internal TextView of the Crouton.
Then you can call Crouton.makeText or Crouton.showText with your
custom Style.
Source
How does MyFonts.getGothamBookBold() look like?
This however should work:
private TextView initializeTextView(final Resources resources) {
TextView text = new TextView(this.activity);
text.setId(TEXT_ID);
text.setText(this.text);
Typeface myTypeFace = Typeface.createFromAsset(this.activity.getAssets(), "gothamBold.ttf");
text.setTypeface(myTypeFace);
text.setGravity(this.style.gravity);
// set the text color if set
if (this.style.textColorResourceId != 0) {
text.setTextColor(resources.getColor(this.style.textColorResourceId));
}

ListView top highlight on scrolling

The border displays a default color (that's orange on my Nexus S) while scrolling a ListView to the limit. How to change that color?
I really don't know how to explain it. Just look at this picture:
So, how to change the highlight color when the ListView scrolling to the border? using themes or styles
The solution is to use setOverscrollFooter(null) and setOverscrollHeader(null).
The documentation is here !
You can also set it directly in the XML :
<ListView android:overScrollMode="never" />
Or specify the footer and the header :
<ListView
android:overscrollHeader="#null"
android:overscrollFooter="#null" />
N.B. : There is also a property fadingEdge that may interest you.
"Overscroll" methodes are supported starting API level 9
Finally I found the solution.
setOverscrollFooter(null) and setOverscrollHeader(null) does not work. At least on 2.3.*. Setting attributes from *.xml doesn't help too.
setOverScrollMode(View.OVER_SCROLL_NEVER) causes glitchy scrolling. At least on 2.3.*.
The only solution that really works involves the use of Java Reflection.
It works even with ugly custom Samsung listviews with bounce overscroll effect.
Here is a snippet:
#Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
//onOverScrolled method must be overrided, or we will see the background of the listview when overscroll fast.
}
private void removeOverscrollEffect() {
try {
Class<?> superClass = getClass().getSuperclass().getSuperclass();
Field field = superClass.getDeclaredField("mEdgeGlowTop");
field.setAccessible(true);
Object edgeGlowTop = field.get(this);
if (edgeGlowTop != null) {
Class<? extends Object> edgeClass = edgeGlowTop.getClass();
Field edgeDrawable = edgeClass.getDeclaredField("mEdge");
edgeDrawable.setAccessible(true);
edgeDrawable.set(edgeGlowTop, new ColorDrawable(Color.TRANSPARENT));
Field glowDrawable = edgeClass.getDeclaredField("mGlow");
glowDrawable.setAccessible(true);
glowDrawable.set(edgeGlowTop, new ColorDrawable(Color.TRANSPARENT));
field.set(this, edgeGlowTop);
}
Field fieldBottom = superClass.getDeclaredField("mEdgeGlowBottom");
fieldBottom.setAccessible(true);
Object edgeGlowBottom = fieldBottom.get(this);
if (edgeGlowBottom != null) {
Class<? extends Object> edgeClassBottom = edgeGlowBottom.getClass();
Field edgeDrawableBottom = edgeClassBottom.getDeclaredField("mEdge");
edgeDrawableBottom.setAccessible(true);
edgeDrawableBottom.set(edgeGlowBottom, new ColorDrawable(Color.TRANSPARENT));
Field glowDrawableBottom = edgeClassBottom.getDeclaredField("mGlow");
glowDrawableBottom.setAccessible(true);
glowDrawableBottom.set(edgeGlowBottom, new ColorDrawable(Color.TRANSPARENT));
fieldBottom.set(this, edgeGlowBottom);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
I hope this helps.
Here is a nice article on ListView Backgrounds Optimization.
To fix this issue, all you have to do is either disable the cache color hint optimization, if you use a non-solid color background, or set the hint to the appropriate solid color value. You can do this from code (see setCacheColorHint(int)) or preferably from XML, by using the android:cacheColorHint attribute. To disable the optimization, simply use the transparent color #00000000. The following screenshot shows a list with android:cacheColorHint="#00000000"
Use it in XML file--
<ListView ---
android:fadingEdge="none"
---</ListView>
EDITED:
Using fading edges may introduce noticeable performance degradations and should be used only when required by the application's visual design. To request fading edges with API level 14 and above, use the android:requiresFadingEdge attribute instead.
Check this API link
I used kord's answer until it stopped working in Lollipop, so I changed into this:
try {
Class<?> superClass = getClass().getSuperclass().getSuperclass();
Field field = superClass.getDeclaredField("mEdgeGlowTop");
field.setAccessible(true);
field.set(this, new NoEdgeEffect(getContext()));
Field fieldBottom = superClass.getDeclaredField("mEdgeGlowBottom");
fieldBottom.setAccessible(true);
fieldBottom.set(this, new NoEdgeEffect(getContext()));
} catch (Exception e) {
}
class NoEdgeEffect extends EdgeEffect
{
public NoEdgeEffect(Context context) {
super(context);
}
public boolean draw(Canvas canvas) {
// Do nothing
return false;
}
}
you can use android:listSelector="#002234".
In above value can be any color code that you can find on internet easily.

Categories

Resources