I want to implement material outlined textbox in Xamarin.Forms. I had created custom renderers but not able to apply style to it.
I want text box like this image https://i.stack.imgur.com/7pWPr.png
By creating custom renderer and inheriting from TextInputLayout displays default material textbox.
https://i.stack.imgur.com/Ek9Vb.jpg
You can use Custom Renderer to custom a View which contained a material designed Entry .
Create a EntryView in Forms:
public class EntryView : ContentView
{
public static readonly BindableProperty TextProperty =
BindableProperty.Create("Text", typeof(string), typeof(EntryView), null);
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
Second , you need to create the EntryViewRenderer in Android :
public class EntryViewRenderer : ViewRenderer
{
global::Android.Views.View view;
global::Android.Widget.EditText editText;
EntryView entryView;
Activity activity;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
if(e.NewElement != null)
{
entryView= e.NewElement as EntryView;
}
if (e.OldElement != null || Element == null)
{
return;
}
try
{
SetupUserInterface();
SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#" ERROR: ", ex.Message);
}
}
private void SetupEventHandlers()
{
editText.TextChanged += EditText_TextChanged;
}
private void EditText_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
entryView.Text = editText.Text;
Console.WriteLine("chanegd +" + entryView.Text);
}
void SetupUserInterface()
{
activity = this.Context as Activity;
view = activity.LayoutInflater.Inflate(Resource.Layout.EntryLayout, this, false);
editText = view.FindViewById<EditText>(Resource.Id.editText1);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);
view.Measure(msw, msh);
view.Layout(0, 0, r - l, b - t);
}
}
In addition , you need to add EntryLayout for this View :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<EditText
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Label"
android:outlineSpotShadowColor="#color/cardview_shadow_start_color"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
Now , you can use it in Xaml of Xamarin Forms :
xmlns:app18="clr-namespace:App18"
<app18:EntryView Text="abc"/>
The effect :
If need to modify color of outline , just add style in Resources/values/styles.xml .
<style name="LoginTextInputLayoutStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense">
<item name="boxStrokeColor">#570dff</item>
<item name="boxStrokeWidth">2dp</item>
<item name="android:textColorHint">#570dff</item>
</style>
In Resources/values/colors.xml add follow code :
<color name="mtrl_textinput_default_box_stroke_color">#570dff</color>
Finally used in EntryLayout.xml :
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/LoginTextInputLayoutStyle">
<EditText
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Label"/>
</android.support.design.widget.TextInputLayout>
The efect:
You can achieve using Grid with some -ve margin value like this:
<Grid>
<Frame Padding="10"
BorderColor="#570dff"
HasShadow="False">
<Entry Placeholder="Enter here"/>
</Frame>
<Label Text=" UserName "
FontSize="15"
TextColor="#570dff"
BackgroundColor="white"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="20,-10,0,0"/>
</Grid>
Output:
<Grid Margin="20">
<Frame Padding="10"
BorderColor="#570dff"
HasShadow="False">
<Entry Placeholder="Enter here"/>
</Frame>
<Label Text=" UserName "
FontSize="15"
TextColor="#570dff"
BackgroundColor="white"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="20,-10,0,0"/>
</Grid>
This is great, it also helped me. I added a Margin of 20 to the grid to make it look better.
Related
I am trying to build a Xamarin.Forms 5 MacOS project - the XAML is the basic as provided by the default boiler plate code.
When I compile the project I get an exception:
The exception:
Cannot convert a NSColorType.Catalog color without specifying the color space, use the overload to specify an NSColorSpace
As I said, I have not added any custom code yet. How do I fix this?
Update
If I downgrade to Xamarin Form 4.8 it builds and runs with no exception:
So why is 5.x failing?
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="VisitsRota.MainPage">
<StackLayout>
<Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
<Label Text="Welcome to Xamarin.Forms!" HorizontalTextAlignment="Center" TextColor="White" FontSize="36"/>
</Frame>
<Label Text="Start developing now" FontSize="Title" Padding="30,10,30,10"/>
<Label Text="Make changes to your XAML file and save to see your UI update in the running app with XAML Hot Reload. Give it a try!" FontSize="16" Padding="30,0,30,0"/>
<Label FontSize="16" Padding="30,24,30,0">
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="Learn more at "/>
<Span Text="https://aka.ms/xamarin-quickstart" FontAttributes="Bold"/>
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ContentPage>
AppDelegate
using AppKit;
using Foundation;
using VisitsRota;
using Xamarin.Forms;
using Xamarin.Forms.Platform.MacOS;
namespace VisitsRota.MacOS
{
[Register("AppDelegate")]
public class AppDelegate : FormsApplicationDelegate
{
NSWindow window;
public AppDelegate()
{
var style = NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Titled;
var rect = new CoreGraphics.CGRect(200, 1000, 1024, 768);
window = new NSWindow(rect, style, NSBackingStore.Buffered, false);
window.Title = "Visits Rota for Mac";
window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
public override NSWindow MainWindow
{
get { return window; }
}
public override void DidFinishLaunching(NSNotification notification)
{
Forms.Init();
LoadApplication(new App());
base.DidFinishLaunching(notification);
}
}
}
The exception is on base.DidFinishLaunching(notification); I think.
Updating to latest Xamarin.Forms resolved this issue.
list.ItemClick+= not working. How I can perform item click on popup window custom listview? In simple listview the itemclick event works, but in the popup window the event is not fired. I need to get the listview item value.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="500dp"
android:gravity="center"
android:descendantFocusability="blocksDescendants"
android:layout_height="wrap_content"
android:background="#android:color/background_light"
android:weightSum="100">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_weight="10"
android:layout_height="40dp">
<TextView
android:text="Vælg din afdeling"
android:textSize="20sp"
android:textColor="#FF222222"
android:paddingLeft="30dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:minHeight="25px"
android:id="#+id/textView1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="10">
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_weight="50">
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:focusable="false"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/listView1" />
</LinearLayout>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="35dp">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:id="#+id/btnAddExpense"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:textColor="#61222222"
android:background="#null"
android:text="Annuller"
android:layout_marginLeft="20dp"
android:layout_gravity="right"
android:layout_marginRight="15dp" />
<Button
android:id="#+id/btnok"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:textColor="#FFF62F5E"
android:text="Gem"
android:background="#null"
android:layout_marginLeft="1dp"
android:layout_gravity="right"
android:layout_marginRight="15dp" />
</LinearLayout>
</LinearLayout>
In this function, I set item click event on listview but it is not working. How can I perform itemclick?
private void DepartmentPicker_Click(object sender, EventArgs e)
{
ButtonNext.Visibility = ViewStates.Invisible;
GetListView.Adapter = new DepartmentListAdapter(this, departments);
bool focusable = true;
int width = 350;// LinearLayout.LayoutParams.WrapContent;
int height = 450;//LinearLayout.LayoutParams.WrapContent;
_view.FindViewById<Button>(Resource.Id.btnok).SetOnClickListener(this);
var list= _view.FindViewById<ListView>(Resource.Id.listView1);
popupWindow = new PopupWindow(_view, width, height, focusable);
popupWindow.ContentView = _view;
popupWindow.ShowAtLocation(_view, GravityFlags.CenterVertical, 0, 0);
popupWindow.Focusable = true;
popupWindow.Touchable = true;
//listView.ChoiceMode = ChoiceMode.Single;
}
I wrote a demo about it, this is running GIF.
There is my code of MainActivity.cs
public class MainActivity : AppCompatActivity
{
List<News> data;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
Button button1 = FindViewById<Button>(Resource.Id.button1);
button1.Click += (o, e) =>
{
var popup = OnClick();
popup.ShowAsDropDown((View)o, 0, 0);
};
data = new List<News>() {
new News ("aaaaaaaa",1200),
new News ("bbbbbbbbb",560),
new News ("ccccccccc",158200),
new News ("ddddddddd",900),
};
// adapter = new NewsAdapter(data, this);
}
private PopupWindow OnClick()
{
PopupWindow _popupWindow = new PopupWindow(this);
LayoutInflater inflater= (LayoutInflater)this.GetSystemService(Context.LayoutInflaterService);
View popup=inflater.Inflate(Resource.Layout.window_popup_content,null);
ListView listView1 = popup.FindViewById<ListView>(Resource.Id.listView1);
NewsAdapter adapter = new NewsAdapter(data, this);
listView1.Adapter = adapter;
listView1.ItemClick += (sender, args) =>
{
Toast.MakeText(this, data[args.Position].Title + "", ToastLength.Short).Show();
_popupWindow.Dismiss();
};
_popupWindow.Width = ViewGroup.LayoutParams.WrapContent;
_popupWindow.Height = ViewGroup.LayoutParams.WrapContent;
_popupWindow.ContentView = popup;
return _popupWindow;
}
}
There is adapter of listview.
public class NewsAdapter : BaseAdapter
{
private List<News> data;
private Context context;
public override int Count
{
get
{
return data.Count;
}
}
public NewsAdapter(List<News> data, Context context)
{
this.data = data;
this.context = context;
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
convertView = LayoutInflater.From(context).Inflate(Resource.Layout.lv_test, parent, false);
TextView title = convertView.FindViewById<TextView>(Resource.Id.tv_title);
TextView pv = convertView.FindViewById<TextView>(Resource.Id.tv_pv);
pv.Text = data[position].Pv.ToString();
title.Text = data[position].Title;
return convertView;
}
xaml of ListviewItem
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
>
<LinearLayout
android:id="#+id/layout_content"
android:layout_width="match_parent"
android:layout_height="30dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="#+id/tv_title"
android:layout_height="20dp"
android:layout_width="0dp"
android:layout_weight="5"
android:textColor="#000000"
android:text="aaaaaaaaa"
android:textSize="16dp" />
<TextView
android:id="#+id/tv_pv"
android:layout_height="10dp"
android:layout_width="0dp"
android:layout_weight="1"
android:textColor="#808080"
android:textSize="10dp"
android:text="19665"
android:gravity="right|center_vertical" />
</LinearLayout>
<View
android:layout_height="1dp"
android:layout_width="match_parent"
android:background="#dedede" />
</LinearLayout>
There is my demo. you could refer to it.
https://github.com/851265601/ListviewPopUpWindowDemo
I have a EntryCell that need to AutoClear each time the user select it. I know how do that on iOS directly but not with Xamarin.Forms.
If you mean clear the value when the Entry is Focused this can be accomplished in a few ways.
The easy way: Handling the Focused event.
<Entry Placeholder="Name" HorizontalOptions="FillAndExpand" Focused="Handle_Focused" />
and in code behind
void Handle_Focused(object sender, Xamarin.Forms.FocusEventArgs e)
{
((Entry)sender).Text = string.Empty;
}
note that you could also use ((Entry)sender).ClearValue(Entry.TextProperty); inside your Handle_Focused method.
Or with the still easy and cleaner way: Using a Behavior
namespace YourRootNamespace.Behaviors
{
public class EntryClearOnFocusBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry bindable)
{
if (bindable == null)
{
throw new InvalidOperationException("Entry was null. Behavior can only be atached to an Entry");
}
bindable.Focused += OnEntryFocused;
base.OnAttachedTo(bindable);
}
protected override void OnDetachingFrom(Entry bindable)
{
bindable.Focused -= OnEntryFocused;
base.OnDetachingFrom(bindable);
}
void OnEntryFocused(object sender, FocusEventArgs e)
{
((Entry)sender).ClearValue(Entry.TextProperty);
}
}
}
Then in your XAML you would:
Add this namespace in your ContentPage definition xmlns:behaviors="clr-namespace:YourRootNamespace.Behaviors"
and attach the behavior to your Entry (or Entries).
<Entry Placeholder="Last Name" HorizontalOptions="FillAndExpand">
<Entry.Behaviors>
<behaviors:EntryClearOnFocusBehavior />
</Entry.Behaviors>
</Entry>
This way is my favorite as it gives you reusability.
You can go one step further and create a Style with this Behavior so attaching the behavior would be as simple as adding an style. More about this here.
Hopes this helps.-
You can use trigger, It is very simple solution
<Entry Placeholder="enter name">
<Entry.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter
Property="Text"
Value="" />
</Trigger>
</Entry.Triggers>
</Entry>
For EntryCell:
XAML code
<ListView x:Name="listView" SeparatorVisibility="None" ItemsSource="{x:Static local:HomeViewModel.lights}">
<ListView.ItemTemplate>
<DataTemplate>
<EntryCell Label="{Binding comment}" Text="{Binding name}" Tapped="Item_Tapped" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code behind
void Item_Tapped(object sender, System.EventArgs e)
{
((EntryCell)sender).Text = "";
}
I have MainViewModel where it shows all the person as a list using recyclerview. Each person has age, gender, name property and also checkbox in order to delete it.
I could not able to figure out how I could able to capture user checkbox event in the MainViewModel?
MainView.axml
<CheckBox
android:id="#+id/checkbox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
local:MvxBind="Checked IsAllSelected" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Name"
android:layout_weight="1" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Age" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="Gender" />
</LinearLayout>
<MvxRecyclerView
android:id="#+id/personRecyclerView"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
local:MvxItemTemplate="#layout/persontemplate"
local:MvxBind="ItemsSource Items; ItemClick ItemSelected" />
</LinearLayout>
PersonTemplate.axml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:gravity="center_vertical"
android:layout_height="60dp">
<CheckBox
android:id="#+id/chked"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
local:MvxBind="Checked IsSelected; Click CheckBoxSelectionCommand;" />
<TextView
android:id="#+id/Name"
android:layout_width="0dp"
android:layout_height="wrap_content"
local:MvxBind="Text Name"
android:layout_weight="1" />
<TextView
android:id="#+id/Age"
android:layout_width="0dp"
android:layout_height="wrap_content"
local:MvxBind="Text Age"
android:layout_weight="1" />
<TextView
android:id="#+id/Gender"
android:layout_width="0dp"
android:layout_height="wrap_content"
local:MvxBind="Text Gender
android:layout_weight="1" />
</LinearLayout>
I am trying to update IsDeleteBtnShow based on the checkbox selection for each item.
MainViewModel.cs
public bool IsAllSelected
{
get { return _isAllSelected; }
set
{
_isAllSelected= value;
Items.ForEach(x => x.IsSelected = _isAllSelected);
IsDeleteBtnShow = _isAllSelected;
RaisePropertyChanged(() => IsAllSelected);
}
}
I have the following viewmodel which is used by RecyclerView to tabulate person as a list.
PersonRecyclerViewModel.cs
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
RaisePropertyChanged(() => IsSelected);
}
}
public ICommand CheckBoxSelectionCommand
{
get
{
return new MvxCommand(() =>
{
var isChecked = IsSelected;
});
}
}
public static PersonViewModel CreateViewModel(Person person)
{
return new PersonViewModel
{
IsSelected = person.IsSelected,
Age= person.Age,
Gender= person.Gender,
Name= entity.Name,
};
}
You can just pass a callback or command to the cration of the ItemViewModel. CreateViewModel(Person person, Action<PersonViewModel> checkboxSelectedCallback) and use it directly as or in CheckBoxSelectionCommand. Something like this:
CheckBoxSelectionCommand
public ICommand CheckBoxSelectionCommand
{
get
{
return new MvxCommand(() =>
{
var isChecked = IsSelected;
ParentCheckBoxSelectionCallback(this);
});
}
}
CreateViewModel
public static PersonViewModel CreateViewModel(Person person, Action<PersonViewModel> checkboxSelectedCallback)
{
return new PersonViewModel
{
IsSelected = entity.IsSelected,
Age = entity.Age,
ParentCheckBoxSelectionCallback = checkboxSelectedCallback,
Gender= entity.Gender,
Name= entity.Name,
};
}
MainViewModel
// only create once.
_checkedChangedCallback = (person =>
{
// do what you have to do if a item got selected
});
// where you create persons
CreateViewModel(person, _checkedChangedCallback );
Another way to do this without adding Actions or any logic in your model is to make your model implement INotifyPropertyChanged:
class PersonRecyclerViewModel : INotifyPropertyChanged
The quickest way to do it is using Fody PropertyChanged because you´ll get the whole implementation of the interface by just adding an attribute to the model:
[ImplementPropertyChanged]
class PersonRecyclerViewModel {}
In your ViewModel, when you get or refresh data source, a for loop would listen for item property changes:
foreach(var item in Items)
{
var n = (INotifyPropertyChanged)item;
n.PropertyChanged += OnItemPropertyChanged;
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
if(propertyChangedEventArgs.PropertyName == "IsSelected")
{
// do whatever you need here
}
}
I have declared a listView like this :
<Mvx.MvxListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/listview"
local:MvxBind="ItemsSource QuestionList; ItemClick ButtonClick"
local:MvxItemTemplate="#layout/item_questions"
android:clickable="true"
android:layout_margin="10dp"
android:layout_marginBottom="20dp" />
Now my item template contains choice mode questions which is rendering as per the requirement but whenever i click on any radio button its not triggering any event. I have take all the selected values from the radio button.
Below is my code of item template:
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/radioButton1"
android:textColor="#000000"
android:clickable="true"
local:MvxBind="Text OptionA; Click ItemChecked" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
local:MvxBind="Text OptionB; Click ItemChecked"
android:id="#+id/radioButton2" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
local:MvxBind="Text OptionC; Click ItemChecked"
android:id="#+id/radioButton3" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
local:MvxBind="Text OptionD; Click ItemChecked"
android:id="#+id/radioButton4" />
</RadioGroup>
I also implemented the wrapper class as suggested. Below is my wrapper class code:
public class ListViewWrapper
{
Question _question;
QuestionsViewModel _parent;
public ListViewWrapper()
{
}
public ListViewWrapper(Question radio, QuestionsViewModel parent)
{
_question = radio;
_parent = parent;
}
public IMvxCommand ItemChecked
{
get
{
return new MvxCommand(() => _parent.btnClick(_question));
}
}
public Question Item
{
get
{
return _question;
}
}
}
Here's ViewModel :
private IMvxCommand _buttonClick;
public IMvxCommand ButtonClick
{
get
{
_buttonClick = _buttonClick ?? new MvxCommand<Question>(btnClick);
return _buttonClick;
}
}
public void btnClick(Question item)
{
//Do something
}