Fixes the image button rendering

vnext
Paul Schneider 8 years ago
parent 210ee87819
commit e781b6bb1b
7 changed files with 433 additions and 9 deletions

@ -343,6 +343,7 @@
<Compile Include="Markdown\MarkdownViewRenderer.cs" />
<Compile Include="Markdown\MarkdownWebChromeClient.cs" />
<Compile Include="OAuth2\YaOAuth2Authenticator.cs" />
<Compile Include="Rendering\ImageButtonRenderer.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SendFilesActivity.cs" />

@ -0,0 +1,256 @@
// ***********************************************************************
// Assembly : XLabs.Forms.Droid
// Author : XLabs Team
// Created : 12-27-2015
//
// Last Modified By : XLabs Team
// Last Modified On : 01-04-2016
// ***********************************************************************
// <copyright file="ImageButtonRenderer.cs" company="XLabs Team">
// Copyright (c) XLabs Team. All rights reserved.
// </copyright>
// <summary>
// This project is licensed under the Apache 2.0 license
// https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/LICENSE
//
// XLabs is a open source project that aims to provide a powerfull and cross
// platform set of controls tailored to work with Xamarin Forms.
// </summary>
// ***********************************************************************
//
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Views;
using XLabs.Enums;
using XLabs.Forms.Extensions;
using Color = Xamarin.Forms.Color;
using View = Android.Views.View;
using BookAStar.Rendering;
using BookAStar.Views;
using Xamarin.Forms.Platform.Android.AppCompat;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using System.IO;
using BookAStar.Helpers;
using System.Reflection;
using System.Threading;
[assembly: ExportRenderer(typeof(ImageButton), typeof(ImageButtonRenderer))]
namespace BookAStar.Rendering
{
/// <summary>
/// Draws a button on the Android platform with the image shown in the right
/// position with the right size.
/// </summary>
public partial class ImageButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
{
private static float _density = float.MinValue;
/// <summary>
/// Sets up the button including the image.
/// </summary>
/// <param name="e">The event arguments.</param>
private ImageButton ImageButton
{
get { return (ImageButton)Element; }
}
protected override async void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
_density = Resources.DisplayMetrics.Density;
var targetButton = Control;
if (targetButton != null) targetButton.SetOnTouchListener(TouchListener.Instance.Value);
if (Element != null && Element.Font != Font.Default && targetButton != null) targetButton.Typeface = Element.Font.ToExtendedTypeface(Context);
if (Element != null && ImageButton.Source != null) await SetImageSourceAsync(targetButton, ImageButton).ConfigureAwait(false);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
if (disposing && Control != null) {
Control.Dispose ();
}
}
/// <summary>
/// Sets the image source.
/// </summary>
/// <param name="targetButton">The target button.</param>
/// <param name="model">The model.</param>
/// <returns>A <see cref="Task"/> for the awaited operation.</returns>
private async Task SetImageSourceAsync(Android.Widget.Button targetButton, ImageButton model)
{
if (targetButton == null || targetButton.Handle == IntPtr.Zero || model == null) return;
// const int Padding = 10;
var source = model.IsEnabled ? model.Source : model.DisabledSource ?? model.Source;
using (var bitmap = await GetBitmapAsync(source))
{
if (bitmap == null)
targetButton.SetCompoundDrawables(null, null, null, null);
else
{
var drawable = new BitmapDrawable(bitmap);
var tintColor = model.IsEnabled ? model.ImageTintColor : model.DisabledImageTintColor;
if (tintColor != Color.Transparent)
{
drawable.SetTint(tintColor.ToAndroid());
drawable.SetTintMode(PorterDuff.Mode.SrcIn);
}
using (var scaledDrawable = GetScaleDrawable(drawable, (int) model.ImageWidthRequest, (int) model.ImageHeightRequest))
{
Drawable left = null;
Drawable right = null;
Drawable top = null;
Drawable bottom = null;
int padding = 2; // model.Padding;
targetButton.CompoundDrawablePadding = RequestToPixels(padding);
targetButton.Gravity = GravityFlags.CenterHorizontal | GravityFlags.CenterVertical;
switch (model.Orientation)
{
case ImageOrientation.ImageToLeft:
left = scaledDrawable;
break;
case ImageOrientation.ImageToRight:
right = scaledDrawable;
break;
case ImageOrientation.ImageOnTop:
top = scaledDrawable;
break;
case ImageOrientation.ImageOnBottom:
bottom = scaledDrawable;
break;
case ImageOrientation.ImageCentered:
top = scaledDrawable;
break;
}
targetButton.SetCompoundDrawables(left, top, right, bottom);
// this.MeasureChildren(model.ImageWidthRequest, model.ImageHeightRequest);
}
}
}
}
/// <summary>
/// Gets a <see cref="Bitmap"/> for the supplied <see cref="ImageSource"/>.
/// </summary>
/// <param name="source">The <see cref="ImageSource"/> to get the image for.</param>
/// <returns>A loaded <see cref="Bitmap"/>.</returns>
private async Task<Bitmap> GetBitmapAsync(ImageSource imagesource)
{
var uriImageLoader = imagesource as UriImageSource;
if (uriImageLoader != null && uriImageLoader.Uri != null)
{
using (var client = UserHelpers.CreateClient())
{
using (var response = await client.GetAsync(uriImageLoader.Uri))
{
var data = await response.Content.ReadAsByteArrayAsync();
return await BitmapFactory.DecodeByteArrayAsync(data, 0, data.Length);
}
}
}
var resImageLoader = imagesource as StreamImageSource;
if (resImageLoader != null && resImageLoader.Stream != null)
{
return await BitmapFactory.DecodeStreamAsync(await resImageLoader.Stream(CancellationToken.None));
}
return null;
}
/// <summary>
/// Called when the underlying model's properties are changed.
/// </summary>
/// <param name="sender">The Model used.</param>
/// <param name="e">The event arguments.</param>
protected override async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == ImageButton.SourceProperty.PropertyName ||
e.PropertyName == ImageButton.DisabledSourceProperty.PropertyName ||
e.PropertyName == VisualElement.IsEnabledProperty.PropertyName ||
e.PropertyName == ImageButton.ImageTintColorProperty.PropertyName ||
e.PropertyName == ImageButton.DisabledImageTintColorProperty.PropertyName)
{
await SetImageSourceAsync(Control, ImageButton).ConfigureAwait(false);
}
}
/// <summary>
/// Returns a <see cref="Drawable"/> with the correct dimensions from an
/// Android resource id.
/// </summary>
/// <param name="drawable">An android <see cref="Drawable"/>.</param>
/// <param name="width">The width to scale to.</param>
/// <param name="height">The height to scale to.</param>
/// <returns>A scaled <see cref="Drawable"/>.</returns>
private Drawable GetScaleDrawable(Drawable drawable, int width, int height)
{
var returnValue = new ScaleDrawable(drawable, 0, 100, 100).Drawable;
returnValue.SetBounds(0, 0, RequestToPixels(width), RequestToPixels(height));
return returnValue;
}
/// <summary>
/// Returns a drawable dimension modified according to the current display DPI.
/// </summary>
/// <param name="sizeRequest">The requested size in relative units.</param>
/// <returns>Size in pixels.</returns>
public int RequestToPixels(int sizeRequest)
{
if (_density == float.MinValue)
{
if (Resources.Handle == IntPtr.Zero || Resources.DisplayMetrics.Handle == IntPtr.Zero)
_density = 1.0f;
else
_density = Resources.DisplayMetrics.Density;
}
return (int)(sizeRequest * _density);
}
}
//Hot fix for the layout positioning issue on Android as described in http://forums.xamarin.com/discussion/20608/fix-for-button-layout-bug-on-android
class TouchListener : Java.Lang.Object, View.IOnTouchListener
{
public static readonly Lazy<TouchListener> Instance = new Lazy<TouchListener>(() => new TouchListener());
/// <summary>
/// Make TouchListener a singleton.
/// </summary>
private TouchListener()
{ }
public bool OnTouch(View v, MotionEvent e)
{
var buttonRenderer = v.Tag as Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer;
if (buttonRenderer != null && e.Action == MotionEventActions.Down) buttonRenderer.Control.Text = buttonRenderer.Element.Text;
return false;
}
}
}

@ -185,6 +185,7 @@
<Compile Include="ViewModels\EstimateAndBilling\EditEstimateViewModel.cs" />
<Compile Include="ViewModels\UserProfile\UserLoginViewModel.cs" />
<Compile Include="ViewModels\ViewModelBase.cs" />
<Compile Include="Views\ImageButton.cs" />
<Compile Include="Views\MarkdownView.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Pages\Oooops\SearchPage.xaml.cs">

@ -13,7 +13,6 @@ namespace BookAStar.Helpers
public static class UserHelpers
{
public static ImageSource Avatar(string avatarPath)
{
var result = avatarPath == null ?

@ -10,15 +10,26 @@
<ScrollView>
<ScrollView.Padding>
<OnPlatform x:TypeArguments="Thickness"
Android="20,20,20,20"
WinPhone="20,20,20,20"
iOS="20,40,20,20" />
</ScrollView.Padding>
<StackLayout BoxView.Color="{StaticResource ContentBackgroundColor}" Spacing="10,10,10,10" >
<StackLayout VisualElement.IsVisible="{Binding HaveAnUser}">
<Label Text="{Binding UserName}" Style="{StaticResource LabelPageHeadingStyle}"
HorizontalTextAlignment="Center"
LineBreakMode="WordWrap" XAlign="Center"
></Label>
<Image Source="{Binding User.AvatarSource}"></Image>
<views:ImageButton
x:Name="AvatarButton"
ImageHeightRequest="80"
ImageWidthRequest="80"
Source="{Binding Avatar}"
IsEnabled="true"
BackgroundColor="#01abdf"
Orientation="ImageToLeft"
Text="{Binding UserName}"
TextColor="#ffffff"></views:ImageButton>
<!--
<controls:ImageButton

@ -11,8 +11,7 @@ namespace BookAStar.Pages.UserProfile
public UserProfilePage()
{
InitializeComponent();
// AvatarButton.Clicked += AvatarButton_Clicked;
AvatarButton.Clicked += AvatarButton_Clicked;
}
private void AvatarButton_Clicked (object sender, EventArgs e)

@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using XLabs.Enums;
namespace BookAStar.Views
{
public class ImageButton : Button
{
/// <summary>
/// Backing field for the Image property.
/// </summary>
public static readonly BindableProperty SourceProperty = BindableProperty.Create(
(Expression<Func<ImageButton, ImageSource>>)(w => w.Source),
null,
BindingMode.OneWay,
null,
(bindable, oldvalue, newvalue) => ((VisualElement)bindable).ToString());
/// <summary>
/// Backing field for the Image property.
/// </summary>
public static readonly BindableProperty DisabledSourceProperty = BindableProperty.Create(
(Expression<Func<ImageButton, ImageSource>>)(w => w.DisabledSource),
null,
BindingMode.OneWay,
null,
(bindable, oldvalue, newvalue) => ((VisualElement)bindable).ToString());
/// <summary>
/// Backing field for the image width property.
/// </summary>
public static readonly BindableProperty ImageWidthRequestProperty =
BindableProperty.Create<ImageButton, int>(
p => p.ImageWidthRequest, default(int));
/// <summary>
/// Backing field for the image height property.
/// </summary>
public static readonly BindableProperty ImageHeightRequestProperty =
BindableProperty.Create<ImageButton, int>(
p => p.ImageHeightRequest, default(int));
/// <summary>
/// Backing field for the orientation property.
/// </summary>
public static readonly BindableProperty OrientationProperty =
BindableProperty.Create<ImageButton, ImageOrientation>(
p => p.Orientation, ImageOrientation.ImageToLeft);
/// <summary>
/// Backing field for the tint color property.
/// </summary>
public static readonly BindableProperty ImageTintColorProperty =
BindableProperty.Create<ImageButton, Color>(
p => p.ImageTintColor, Color.Transparent);
/// <summary>
/// Backing field for the disbaled tint color property.
/// </summary>
public static readonly BindableProperty DisabledImageTintColorProperty =
BindableProperty.Create<ImageButton, Color>(
p => p.DisabledImageTintColor, Color.Transparent);
/// <summary>
/// Gets or sets the ImageSource to use with the control.
/// </summary>
/// <value>
/// The Source property gets/sets the value of the backing field, SourceProperty.
/// </value>
[TypeConverter(typeof(ImageSourceConverter))]
public ImageSource Source
{
get { return (ImageSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
/// <summary>
/// Gets or sets the ImageSource to use with the control.
/// </summary>
/// <value>
/// The Source property gets/sets the value of the backing field, SourceProperty.
/// </value>
[TypeConverter(typeof(ImageSourceConverter))]
public ImageSource DisabledSource
{
get { return (ImageSource)GetValue(DisabledSourceProperty); }
set { SetValue(DisabledSourceProperty, value); }
}
/// <summary>
/// Gets or sets The orientation of the image relative to the text.
/// </summary>
/// <value>
/// The Orientation property gets/sets the value of the backing field, OrientationProperty.
/// </value>
public ImageOrientation Orientation
{
get { return (ImageOrientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
/// <summary>
/// Gets or sets the requested height of the image. If less than or equal to zero than a
/// height of 50 will be used.
/// </summary>
/// <value>
/// The ImageHeightRequest property gets/sets the value of the backing field, ImageHeightRequestProperty.
/// </value>
public int ImageHeightRequest
{
get { return (int)GetValue(ImageHeightRequestProperty); }
set { SetValue(ImageHeightRequestProperty, value); }
}
/// <summary>
/// Gets or sets the requested width of the image. If less than or equal to zero than a
/// width of 50 will be used.
/// </summary>
/// <value>
/// The ImageHeightRequest property gets/sets the value of the backing field, ImageHeightRequestProperty.
/// </value>
public int ImageWidthRequest
{
get { return (int)GetValue(ImageWidthRequestProperty); }
set { SetValue(ImageWidthRequestProperty, value); }
}
/// <summary>
/// Gets or sets the tint color of the image
/// </summary>
/// <value>
/// The ImageTintColor property gets/sets the value of the backing field, ImageTintColorProperty.
/// </value>
public Color ImageTintColor
{
get { return (Color)GetValue(ImageTintColorProperty); }
set { SetValue(ImageTintColorProperty, value); }
}
/// <summary>
/// Gets or sets the tint color of the image when the button is disabled
/// </summary>
/// <value>
/// The DisabledImageTintColor property gets/sets the value of the backing field, DisabledImageTintColorProperty.
/// </value>
public Color DisabledImageTintColor
{
get { return (Color)GetValue(DisabledImageTintColorProperty); }
set { SetValue(DisabledImageTintColorProperty, value); }
}
}
}
Loading…