Fala galera,
Tentando manter a periodicidade semanal chegamos novamente com uma dica rápida de Xamarin.Forms!
A ideia é ser um artigo bem rápido e todas as dicas vão ficar em um único repositório, se você perdeu algum veja as que ja saíram :
· Xamarin Rocket #1 — LineBreakMode
· Xamarin Rocket #2 — Alterando o espaço das linhas e colunas do Grid
· Xamarin Rocket #3 — Tela Cheia, ocultando a barra de status
· Xamarin Rocket #4 — Imagens em botões
· Xamarin Rocket #5 — Notificação ao alterar a conexão
Muitas pessoas ja viram aquele indicador de progresso em Aplicativos, principalmente de exercício ( No meu caso só vi mesmo, porque fazer exercício .. bem hahuahahuaa ) .
Hoje vou lhes mostrar um código bem legal, que precisei utilizar em um App e pode ser muito útil para vocês para gerar um indicador de progresso.
Para ajudar em nosso controle vamos utilizar o incrível SkiaSharp!
Se você não conhece o SkiaSharp :
O SkiaSharp é uma API de gráficos 2D multiplataforma para plataformas .NET ,baseada na Biblioteca de Gráficos Skia do Google. Ele fornece uma API 2D abrangente que pode ser usada em mobile, e desktop para renderizar imagens.
Em resumo com o SkiaSharp, poremos criar controles com Modelos 2D. Muito útil para exibir gráficos por exemplo 😉
O Microcharts que demonstrei nesse artigo utiliza o SkiaSharp como base.
Agora vamos utiliza-lo para nos ajudar e criar o Indicador.
Criando nosso Indicador
Vamos ao nuget Baixar o pacote SkiaSharp.Views.Forms e instalar no projeto compartilhado :
Vamos criar um Helper que vai nos ajudar a pegar os tamanhos das telas para o controle ficar correto :
using System;
using System.Diagnostics;
namespace XamarinRocket
{
public class ProgressHelpers
{
// Reference Values(Standard Pixel 1 Device)
private const float refHeight = 1080;//1677;
private const float refWidth = 632;//940;
// Derived Proportinate Values
private float deviceHeight = 1; // Initializing to 1
private float deviceWidth = 1; // Initializing to 1
public ProgressHelpers() { }
public void SetDevice(int deviceHeight, int deviceWidth)
{
this.deviceHeight = deviceHeight;
this.deviceWidth = deviceWidth;
}
public float GetFactoredValue(int value)
{
float refRatio = refHeight / refWidth;
float devRatio = deviceHeight / deviceWidth;
float factoredValue = value * (refRatio / devRatio);
return factoredValue;
}
public float GetFactoredHeight(int value)
{
return (float)((value / refHeight) * deviceHeight);
}
public float GetFactoredWidth(int value)
{
return (float)((value / refWidth) * deviceWidth);
}
public int GetSweepAngle(int goal, int achieved)
{
int SweepAngle = 260;
float factor = (float)achieved / goal;
return (int)(SweepAngle * factor);
}
}
}
Agora vamos criar nossa pagina utilizando o namespace : xmlns:skia=”clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms” para utilizar o Skiasharp , SKCanvasView :
<?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="XamarinRocket.Views.XamarinRocket8Page" xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="6*" />
<RowDefinition Height="10*" />
</Grid.RowDefinitions>
<skia:SKCanvasView x:Name="canvas"
PaintSurface="OnCanvasViewPaintSurfaceAsync"
Grid.Row="0"
BackgroundColor="#ecf0f1"/>
<StackLayout Orientation="Vertical" Grid.Row="1" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="White" >
<StackLayout Orientation="Horizontal" HorizontalOptions="Center" BackgroundColor="White" Padding="0,5,10,5">
<Label Text=" Hoje"/>
<Switch x:Name="sw_listToggle" IsToggled="{Binding Path=Monitored, Mode=TwoWay}"
Toggled="SwitchToggledAsync" />
<Label Text="Mês"/>
</StackLayout>
<Slider x:Name="sweepAngleSlider"
ValueChanged="SliderValueChanged"
Minimum="0" Maximum="260"
IsVisible="true"/>
</StackLayout>
</Grid>
</ContentPage>
Nessa mesma pagina vamos adicionar um Switch e um Slider para manipular nosso controle.
Em seguida vamos implementar o backEnd ,para gerar o controle :
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using SkiaSharp;
using SkiaSharp.Views.Forms;
using Xamarin.Forms;
namespace XamarinRocket.Views
{
public partial class XamarinRocket8Page : ContentPage
{
SKPaintSurfaceEventArgs args;
ProgressHelpers progressHelpers = new ProgressHelpers();
int exercicioDiario = 20;
int exercicioMensal = 340;
int meta = 900;
public XamarinRocket8Page()
{
InitializeComponent();
InitiateProgressUpdate();
}
void OnCanvasViewPaintSurfaceAsync(object sender, SKPaintSurfaceEventArgs args1)
{
args = args1;
DrawGaugeAsync();
}
async void SwitchToggledAsync(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
await InitiateProgressUpdate();
}
void SliderValueChanged(object sender, ValueChangedEventArgs args)
{
if (canvas != null)
{
canvas.InvalidateSurface();
}
}
async Task AnimateProgress(int progress)
{
sw_listToggle.IsEnabled = false;
sweepAngleSlider.Value = 1;
for (int i = 0; i < progress; i = i + 5)
{
sweepAngleSlider.Value = i;
await Task.Delay(3);
}
sweepAngleSlider.Value = progress;
sw_listToggle.IsEnabled = true;
}
async Task InitiateProgressUpdate()
{
if (sw_listToggle.IsToggled)
await AnimateProgress(progressHelpers.GetSweepAngle(meta, exercicioMensal));
else
await AnimateProgress(progressHelpers.GetSweepAngle(meta / 30, exercicioDiario));
}
public void DrawGaugeAsync()
{
int uPadding = 150;
int side = 500;
int radialGaugeWidth = 25;
int lineSize1 = 220;
int lineSize2 = 70;
int lineSize3 = 80;
int lineHeight1 = 100;
int lineHeight2 = 200;
int lineHeight3 = 300;
float startAngle = -220;
float sweepAngle = 260;
try
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
progressHelpers.SetDevice(info.Height, info.Width);
canvas.Clear();
float upperPading = progressHelpers.GetFactoredHeight(uPadding);
int Xc = info.Width / 2;
float Yc = progressHelpers.GetFactoredHeight(side);
int X1 = (int)(Xc - Yc);
int Y1 = (int)(Yc - Yc + upperPading);
int X2 = (int)(Xc + Yc);
int Y2 = (int)(Yc + Yc + upperPading);
SKPaint paint1 = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = Color.FromHex("#e0dfdf").ToSKColor(),
StrokeWidth = progressHelpers.GetFactoredWidth(radialGaugeWidth),
StrokeCap = SKStrokeCap.Round
};
SKPaint paint2 = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = Color.FromHex("#05c782").ToSKColor(),
StrokeWidth = progressHelpers.GetFactoredWidth(radialGaugeWidth),
StrokeCap = SKStrokeCap.Round
};
SKRect rect = new SKRect(X1, Y1, X2, Y2);
SKPath path1 = new SKPath();
path1.AddArc(rect, startAngle, sweepAngle);
canvas.DrawPath(path1, paint1);
SKPath path2 = new SKPath();
path2.AddArc(rect, startAngle, (float)sweepAngleSlider.Value);
canvas.DrawPath(path2, paint2);
using (SKPaint skPaint = new SKPaint())
{
skPaint.Style = SKPaintStyle.Fill;
skPaint.IsAntialias = true;
skPaint.Color = SKColor.Parse("#676a69");
skPaint.TextAlign = SKTextAlign.Center;
skPaint.TextSize = progressHelpers.GetFactoredHeight(lineSize1);
skPaint.Typeface = SKTypeface.FromFamilyName(
"Arial",
SKFontStyleWeight.Bold,
SKFontStyleWidth.Normal,
SKFontStyleSlant.Upright);
if (sw_listToggle.IsToggled)
canvas.DrawText(exercicioMensal + "", Xc, Yc + progressHelpers.GetFactoredHeight(lineHeight1), skPaint);
else
canvas.DrawText(exercicioDiario + "", Xc, Yc + progressHelpers.GetFactoredHeight(lineHeight1), skPaint);
}
using (SKPaint skPaint = new SKPaint())
{
skPaint.Style = SKPaintStyle.Fill;
skPaint.IsAntialias = true;
skPaint.Color = SKColor.Parse("#676a69");
skPaint.TextAlign = SKTextAlign.Center;
skPaint.TextSize = progressHelpers.GetFactoredHeight(lineSize2);
canvas.DrawText("Minutos", Xc, Yc + progressHelpers.GetFactoredHeight(lineHeight2), skPaint);
}
using (SKPaint skPaint = new SKPaint())
{
skPaint.Style = SKPaintStyle.Fill;
skPaint.IsAntialias = true;
skPaint.Color = SKColor.Parse("#e2797a");
skPaint.TextAlign = SKTextAlign.Center;
skPaint.TextSize = progressHelpers.GetFactoredHeight(lineSize3);
if (sw_listToggle.IsToggled)
canvas.DrawText("Meta " + meta + " Min", Xc, Yc + progressHelpers.GetFactoredHeight(lineHeight3), skPaint);
else
{
canvas.DrawText("Meta " + meta / 30 + " Min", Xc, Yc + progressHelpers.GetFactoredHeight(lineHeight3), skPaint);
}
}
}
catch (Exception e)
{
Debug.WriteLine(e.StackTrace);
}
}
}
}
O que estamos fazendo ? Estamos utilizando o SkiaSharp para gerar um desenho 2D de um controle de indicador. Apenas para demonstrar o switch indica se você quer ver o Progresso Diário ou Mensal e chama o método : InitiateProgressUpdate.
O método DrawGaugeAsync cria todos os vetores necessários para exibir o controle. Com isto é possível demonstrar a flexibilidade do Skiasharp, você pode customizar seu controle da forma que desejar.
Vamos rodar :
Skiasharp é muito poderoso, e com criatividade é possível criar controles incríveis como o acima 🙂
Caso queira baixar o código utilizado no Exemplo: Clique aqui.
Quer ver outros artigos sobre Xamarin ? Clique aqui.
Espero ter ajudado!
Aquele abraço!