SkiaSharp bit eşlem döşeme
Önceki iki makalede gördüğünüz gibi, SKShader
sınıf doğrusal veya döngüsel gradyanlar oluşturabilir. Bu makalede, bir alanı döşemek için bit eşlem kullanan nesneye odaklanılır SKShader
. Bit eşlem, özgün yönlendirmesinde yatay ve dikey olarak yinelenebilir veya alternatif olarak yatay ve dikey olarak çevrilebilir. Çevirme, kutucuklar arasındaki kesintileri önler:
Bu gölgelendiriciyi oluşturan statik SKShader.CreateBitmap
yöntemin bir SKBitmap
parametresi ve numaralandırmanın SKShaderTileMode
iki üyesi vardır:
public static SKShader CreateBitmap (SKBitmap src, SKShaderTileMode tmx, SKShaderTileMode tmy)
İki parametre, yatay döşeme ve dikey döşeme için kullanılan modları gösterir. Bu, SKShaderTileMode
gradyan yöntemleriyle de kullanılan sabit listesidir.
Aşırı CreateBitmap
yükleme, kutucuklu bit eşlemlerde dönüşüm gerçekleştirmek için bir SKMatrix
bağımsız değişken içerir:
public static SKShader CreateBitmap (SKBitmap src, SKShaderTileMode tmx, SKShaderTileMode tmy, SKMatrix localMatrix)
Bu makale, bu matris dönüşümünü kutucuklu bit eşlemlerle kullanmaya yönelik çeşitli örnekler içerir.
Kutucuk modlarını keşfetme
Örneğin Gölgelendiriciler ve diğer Efektler sayfasının Bit Eşlem Döşemesi bölümündeki ilk program, iki SKShaderTileMode
bağımsız değişkenin etkilerini gösterir. Bit Eşlem Kutucuğu Çevirme Modları XAML dosyası, yatay ve dikey döşeme için bir değer seçmenize olanak sağlayan bir SKShaderTilerMode
ve iki Picker
görünümün örneğini SKCanvasView
oluşturur. Üyelerin bir dizisinin SKShaderTileMode
bölümünde tanımlandığına Resources
dikkat edin:
<?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:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
xmlns:skiaforms="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
x:Class="SkiaSharpFormsDemos.Effects.BitmapTileFlipModesPage"
Title="Bitmap Tile Flip Modes">
<ContentPage.Resources>
<x:Array x:Key="tileModes"
Type="{x:Type skia:SKShaderTileMode}">
<x:Static Member="skia:SKShaderTileMode.Clamp" />
<x:Static Member="skia:SKShaderTileMode.Repeat" />
<x:Static Member="skia:SKShaderTileMode.Mirror" />
</x:Array>
</ContentPage.Resources>
<StackLayout>
<skiaforms:SKCanvasView x:Name="canvasView"
VerticalOptions="FillAndExpand"
PaintSurface="OnCanvasViewPaintSurface" />
<Picker x:Name="xModePicker"
Title="Tile X Mode"
Margin="10, 0"
ItemsSource="{StaticResource tileModes}"
SelectedIndex="0"
SelectedIndexChanged="OnPickerSelectedIndexChanged" />
<Picker x:Name="yModePicker"
Title="Tile Y Mode"
Margin="10, 10"
ItemsSource="{StaticResource tileModes}"
SelectedIndex="0"
SelectedIndexChanged="OnPickerSelectedIndexChanged" />
</StackLayout>
</ContentPage>
Arka planda kod dosyasının oluşturucusunun, bir maymunun oturduğunu gösteren bit eşlem kaynağına yüklenmesi. Önce yöntemini SKBitmap
kullanarak ExtractSubset
görüntüyü kırparak baş ve ayakların bit eşlem kenarlarına dokunmasını sağlar. Oluşturucu daha sonra yöntemini kullanarak boyutunun Resize
yarısına sahip başka bir bit eşlem oluşturur. Bu değişiklikler bit eşlemi döşeme için biraz daha uygun hale getirir:
public partial class BitmapTileFlipModesPage : ContentPage
{
SKBitmap bitmap;
public BitmapTileFlipModesPage ()
{
InitializeComponent ();
SKBitmap origBitmap = BitmapExtensions.LoadBitmapResource(
GetType(), "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg");
// Define cropping rect
SKRectI cropRect = new SKRectI(5, 27, 296, 260);
// Get the cropped bitmap
SKBitmap croppedBitmap = new SKBitmap(cropRect.Width, cropRect.Height);
origBitmap.ExtractSubset(croppedBitmap, cropRect);
// Resize to half the width and height
SKImageInfo info = new SKImageInfo(cropRect.Width / 2, cropRect.Height / 2);
bitmap = croppedBitmap.Resize(info, SKBitmapResizeMethod.Box);
}
void OnPickerSelectedIndexChanged(object sender, EventArgs args)
{
canvasView.InvalidateSurface();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Get tile modes from Pickers
SKShaderTileMode xTileMode =
(SKShaderTileMode)(xModePicker.SelectedIndex == -1 ?
0 : xModePicker.SelectedItem);
SKShaderTileMode yTileMode =
(SKShaderTileMode)(yModePicker.SelectedIndex == -1 ?
0 : yModePicker.SelectedItem);
using (SKPaint paint = new SKPaint())
{
paint.Shader = SKShader.CreateBitmap(bitmap, xTileMode, yTileMode);
canvas.DrawRect(info.Rect, paint);
}
}
}
İşleyici, PaintSurface
ayarları iki Picker
görünümden alır SKShaderTileMode
ve bit eşlem ile bu iki değeri temel alan bir SKShader
nesne oluşturur. Bu gölgelendirici tuvali doldurmak için kullanılır:
Soldaki iOS ekranı varsayılan değerlerinin SKShaderTileMode.Clamp
etkisini gösterir. Bit eşlem sol üst köşede yer alır. Bit eşlem altında, piksellerin alt satırı aşağı doğru yinelenir. Bit eşlemin sağındaki en sağdaki piksel sütunu, tüm yol boyunca yinelenir. Tuvalin geri kalanı bit eşleminin sağ alt köşesindeki koyu kahverengi pikselle renklendirilir. Seçeneğin Clamp
bit eşlem döşemesi ile neredeyse hiç kullanılmadığının açık olması gerekir!
Ortadaki Android ekranı, her iki bağımsız değişkenin SKShaderTileMode.Repeat
sonucunu gösterir. Kutucuk yatay ve dikey olarak yinelenir. Evrensel Windows Platformu ekranında gösterilirSKShaderTileMode.Mirror
. Kutucuklar yinelenir, ancak yatay ve dikey olarak alternatif olarak çevrilmiş olur. Bu seçeneğin avantajı, kutucuklar arasında kesinti olmamasıdır.
Yatay ve dikey yineleme için farklı seçenekler kullanabileceğinizi unutmayın. öğesinin ikinci bağımsız değişkeni olarak ancak SKShaderTileMode.Repeat
üçüncü bağımsız değişken CreateBitmap
olarak belirtebilirsinizSKShaderTileMode.Mirror
. Her satırda, maymunlar normal görüntü ile ayna görüntüsü arasında hala alternatiftir, ancak maymunların hiçbiri baş aşağı değil.
Desenli arka planlar
Bit eşlem döşemesi genellikle nispeten küçük bir bit eşlemden desenli arka plan oluşturmak için kullanılır. Klasik örnek bir tuğla duvardır.
Algoritmik Tuğla Duvar sayfası, bir bütün tuğlaya benzeyen küçük bir bit eşlem ve harçla ayrılmış bir tuğlanın iki yarısı oluşturur. Bu tuğla bir sonraki örnekte de kullanıldığından, statik bir oluşturucu tarafından oluşturulur ve statik bir özellik ile genel kullanıma sunar:
public class AlgorithmicBrickWallPage : ContentPage
{
static AlgorithmicBrickWallPage()
{
const int brickWidth = 64;
const int brickHeight = 24;
const int morterThickness = 6;
const int bitmapWidth = brickWidth + morterThickness;
const int bitmapHeight = 2 * (brickHeight + morterThickness);
SKBitmap bitmap = new SKBitmap(bitmapWidth, bitmapHeight);
using (SKCanvas canvas = new SKCanvas(bitmap))
using (SKPaint brickPaint = new SKPaint())
{
brickPaint.Color = new SKColor(0xB2, 0x22, 0x22);
canvas.Clear(new SKColor(0xF0, 0xEA, 0xD6));
canvas.DrawRect(new SKRect(morterThickness / 2,
morterThickness / 2,
morterThickness / 2 + brickWidth,
morterThickness / 2 + brickHeight),
brickPaint);
int ySecondBrick = 3 * morterThickness / 2 + brickHeight;
canvas.DrawRect(new SKRect(0,
ySecondBrick,
bitmapWidth / 2 - morterThickness / 2,
ySecondBrick + brickHeight),
brickPaint);
canvas.DrawRect(new SKRect(bitmapWidth / 2 + morterThickness / 2,
ySecondBrick,
bitmapWidth,
ySecondBrick + brickHeight),
brickPaint);
}
// Save as public property for other programs
BrickWallTile = bitmap;
}
public static SKBitmap BrickWallTile { private set; get; }
···
}
Sonuçta elde edilen bit eşlem 70 piksel genişliğinde ve 60 piksel yüksekliğindedir:
Algoritmik Tuğla Duvar sayfasının geri kalanı, bu görüntüyü yatay ve dikey olarak tekrarlayan bir SKShader
nesne oluşturur:
public class AlgorithmicBrickWallPage : ContentPage
{
···
public AlgorithmicBrickWallPage ()
{
Title = "Algorithmic Brick Wall";
// Create SKCanvasView
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
// Create bitmap tiling
paint.Shader = SKShader.CreateBitmap(BrickWallTile,
SKShaderTileMode.Repeat,
SKShaderTileMode.Repeat);
// Draw background
canvas.DrawRect(info.Rect, paint);
}
}
}
Sonuç şu şekildedir:
Biraz daha gerçekçi bir şey tercih edebilirsiniz. Bu durumda, gerçek bir tuğla duvarın fotoğrafını çekebilir ve sonra kırpabilirsiniz. Bu bit eşlem 300 piksel genişliğinde ve 150 piksel yüksekliğindedir:
Bu bit eşlem, FotoğrafIk Tuğla Duvar sayfasında kullanılır:
public class PhotographicBrickWallPage : ContentPage
{
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(PhotographicBrickWallPage),
"SkiaSharpFormsDemos.Media.BrickWallTile.jpg");
public PhotographicBrickWallPage()
{
Title = "Photographic Brick Wall";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
// Create bitmap tiling
paint.Shader = SKShader.CreateBitmap(bitmap,
SKShaderTileMode.Mirror,
SKShaderTileMode.Mirror);
// Draw background
canvas.DrawRect(info.Rect, paint);
}
}
}
bağımsız değişkenlerinin SKShaderTileMode
CreateBitmap
her ikisi de Mirror
olduğuna dikkat edin. Bu seçenek genellikle gerçek dünya görüntülerinden oluşturulan kutucukları kullandığınızda gereklidir. Kutucukların yansıtılması kesintileri önler:
Kutucuk için uygun bir bit eşlem elde etmek için bazı çalışmalar gereklidir. Bu çok iyi çalışmıyor çünkü koyu tuğla çok fazla göze çarpıyor. Tekrarlanan görüntülerde düzenli olarak görünür ve bu tuğla duvarın daha küçük bir bit eşlemden oluşturulduğu gerçeği ortaya çıkar.
Örneğin Media klasörü, taş bir duvarın bu görüntüsünü de içerir:
Ancak, özgün bit eşlem bir kutucuk için biraz fazla büyük. Yeniden boyutlandırılabilir, ancak SKShader.CreateBitmap
yöntemi kutucuğa bir dönüşüm uygulayarak kutucuğu yeniden boyutlandırabilir. Bu seçenek Taş Duvar sayfasında gösterilmiştir:
public class StoneWallPage : ContentPage
{
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(StoneWallPage),
"SkiaSharpFormsDemos.Media.StoneWallTile.jpg");
public StoneWallPage()
{
Title = "Stone Wall";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
// Create scale transform
SKMatrix matrix = SKMatrix.MakeScale(0.5f, 0.5f);
// Create bitmap tiling
paint.Shader = SKShader.CreateBitmap(bitmap,
SKShaderTileMode.Mirror,
SKShaderTileMode.Mirror,
matrix);
// Draw background
canvas.DrawRect(info.Rect, paint);
}
}
}
SKMatrix
Görüntüyü özgün boyutunun yarısına ölçeklendirmek için bir değer oluşturulur:
Dönüştürme yönteminde kullanılan özgün bit eşlem üzerinde CreateBitmap
çalışır mı? Yoksa sonuçta elde edilen kutucuk dizisini mi dönüştürüyor?
Bu soruyu yanıtlamanın kolay bir yolu, dönüşümün bir parçası olarak döndürme eklemektir:
SKMatrix matrix = SKMatrix.MakeScale(0.5f, 0.5f);
SKMatrix.PostConcat(ref matrix, SKMatrix.MakeRotationDegrees(15));
Dönüşüm tek tek kutucuğa uygulanırsa, kutucuğun yinelenen her görüntüsü döndürülmelidir ve sonuç birçok kesinti içerir. Ancak bu ekran görüntüsünde bileşik kutucuk dizisinin dönüştürüldüğü açıktır:
Kutucuk hizalama bölümünde gölgelendiriciye uygulanan bir çeviri dönüştürme örneği göreceksiniz.
Örnek, bu 240 piksel kare bit eşlem temelinde bit eşlem döşemesi kullanarak ahşap taneli arka plan benzetimi sağlar:
Bu bir ahşap zemin fotoğrafı. seçeneği SKShaderTileMode.Mirror
, çok daha büyük bir ahşap alanı olarak görünmesini sağlar:
Kutucuk hizalaması
Şimdiye kadar gösterilen tüm örnekler, tuvalin tamamını kapsayacak şekilde tarafından SKShader.CreateBitmap
oluşturulan gölgelendiriciyi kullanmıştır. Çoğu durumda, daha küçük alanları dosyalama için bit eşlem döşemesi veya kalın çizgilerin iç kısımlarını doldurmak için (daha nadiren) kullanacaksınız. Daha küçük bir dikdörtgen için kullanılan fotoğrafik tuğla duvar kutucuğu aşağıdadır:
Bu size iyi görünebilir ya da olmayabilir. Belki de döşeme deseninin dikdörtgenin sol üst köşesindeki dolu bir tuğlayla başlamaması sizi rahatsız ediyor. Bunun nedeni gölgelendiricilerin süsledikleri grafik nesneyle değil tuvalle hizalanmış olmasıdır.
Düzeltme basittir. SKMatrix
Çeviri dönüşümünü temel alan bir değer oluşturun. Dönüşüm, kutucuklu deseni, kutucuğun sol üst köşesinin hizalanmasını istediğiniz noktaya etkili bir şekilde kaydırır. Bu yaklaşım, yukarıda gösterilen hizalanmamış kutucukların görüntüsünü oluşturan Kutucuk Hizalama sayfasında gösterilmiştir:
public class TileAlignmentPage : ContentPage
{
bool isAligned;
public TileAlignmentPage()
{
Title = "Tile Alignment";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
// Add tap handler
TapGestureRecognizer tap = new TapGestureRecognizer();
tap.Tapped += (sender, args) =>
{
isAligned ^= true;
canvasView.InvalidateSurface();
};
canvasView.GestureRecognizers.Add(tap);
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
SKRect rect = new SKRect(info.Width / 7,
info.Height / 7,
6 * info.Width / 7,
6 * info.Height / 7);
// Get bitmap from other program
SKBitmap bitmap = AlgorithmicBrickWallPage.BrickWallTile;
// Create bitmap tiling
if (!isAligned)
{
paint.Shader = SKShader.CreateBitmap(bitmap,
SKShaderTileMode.Repeat,
SKShaderTileMode.Repeat);
}
else
{
SKMatrix matrix = SKMatrix.MakeTranslation(rect.Left, rect.Top);
paint.Shader = SKShader.CreateBitmap(bitmap,
SKShaderTileMode.Repeat,
SKShaderTileMode.Repeat,
matrix);
}
// Draw rectangle
canvas.DrawRect(rect, paint);
}
}
}
Kutucuk Hizalama sayfası bir TapGestureRecognizer
içerir. Ekrana dokunun veya tıklayın; program bir SKMatrix
bağımsız değişkenle yönteme SKShader.CreateBitmap
geçer. Bu dönüşüm, deseni kaydırır, böylece sol üst köşe tam tuğla içerir:
Kutucuklu bit eşlem deseninin boyanacak alan içinde ortalandığından emin olmak için de bu tekniği kullanabilirsiniz. Ortalanmış Kutucuklar sayfasında, PaintSurface
işleyici önce koordinatları tuvalin ortasında tek bit eşlemi görüntüleyecekmiş gibi hesaplar. Ardından bu koordinatları kullanarak için SKShader.CreateBitmap
bir çeviri dönüşümü oluşturur. Bu dönüşüm, bir kutucuğun ortalanmış olması için desenin tamamını kaydırır:
public class CenteredTilesPage : ContentPage
{
SKBitmap bitmap = BitmapExtensions.LoadBitmapResource(
typeof(CenteredTilesPage),
"SkiaSharpFormsDemos.Media.monkey.png");
public CenteredTilesPage ()
{
Title = "Centered Tiles";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Find coordinates to center bitmap in canvas...
float x = (info.Width - bitmap.Width) / 2f;
float y = (info.Height - bitmap.Height) / 2f;
using (SKPaint paint = new SKPaint())
{
// ... but use them to create a translate transform
SKMatrix matrix = SKMatrix.MakeTranslation(x, y);
paint.Shader = SKShader.CreateBitmap(bitmap,
SKShaderTileMode.Repeat,
SKShaderTileMode.Repeat,
matrix);
// Use that tiled bitmap pattern to fill a circle
canvas.DrawCircle(info.Rect.MidX, info.Rect.MidY,
Math.Min(info.Width, info.Height) / 2,
paint);
}
}
}
İşleyici, PaintSurface
tuvalin ortasına bir daire çizerek sonuç alır. Elbette, kutucuklardan biri dairenin tam ortasındadır ve diğerleri simetrik bir düzende düzenlenmiştir:
Başka bir merkezleme yaklaşımı aslında biraz daha kolaydır. Kutucuğu ortaya koyan bir çeviri dönüşümü oluşturmak yerine, kutucuklu desenin bir köşesini ortalayabilirsiniz. Çağrısında SKMatrix.MakeTranslation
, tuvalin merkezi için bağımsız değişkenleri kullanın:
SKMatrix matrix = SKMatrix.MakeTranslation(info.Rect.MidX, info.Rect.MidY);
Desen yine ortalanmış ve simetriktir, ancak ortada hiçbir kutucuk yoktur:
Döndürme yoluyla basitleştirme
Bazen yönteminde SKShader.CreateBitmap
döndürme dönüşümü kullanmak bit eşlem kutucuğunu basitleştirebilir. Zincir bağlantı çiti için bir kutucuk tanımlamaya çalışırken bu durum ortaya çıkıyor. ChainLinkTile.cs dosyası burada gösterilen kutucuğu oluşturur (netlik amacıyla pembe arka plan ile):
Kutucuğun iki bağlantı içermesi gerekir, böylece kod kutucuğu dört çeyrekte böler. Sol üst ve sağ alt kadranlar aynıdır, ancak tam değildir. Tellerin sağ üst ve sol alt kadranlarında ek çizimlerle işlenmesi gereken küçük çentikler vardır. Tüm bu işi yapar dosya 174 satır uzunluğundadır.
Bu kutucuğu oluşturmak çok daha kolay hale gelecektir:
Bit eşlem kutucuğu gölgelendiricisi 90 derece döndürülürse görseller neredeyse aynıdır.
Daha kolay zincir bağlantısı kutucuğunu oluşturma kodu, Zincir Bağlantı Kutucuğu sayfasının bir parçasıdır. Oluşturucu, programın üzerinde çalıştığı cihaz türüne göre bir kutucuk boyutu belirler ve ardından bit eşlem üzerinde çizgiler, yollar ve gradyan gölgelendiriciler kullanarak çizen öğesini çağırır CreateChainLinkTile
:
public class ChainLinkFencePage : ContentPage
{
···
SKBitmap tileBitmap;
public ChainLinkFencePage ()
{
Title = "Chain-Link Fence";
// Create bitmap for chain-link tiling
int tileSize = Device.Idiom == TargetIdiom.Desktop ? 64 : 128;
tileBitmap = CreateChainLinkTile(tileSize);
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
SKBitmap CreateChainLinkTile(int tileSize)
{
tileBitmap = new SKBitmap(tileSize, tileSize);
float wireThickness = tileSize / 12f;
using (SKCanvas canvas = new SKCanvas(tileBitmap))
using (SKPaint paint = new SKPaint())
{
canvas.Clear();
paint.Style = SKPaintStyle.Stroke;
paint.StrokeWidth = wireThickness;
paint.IsAntialias = true;
// Draw straight wires first
paint.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0),
new SKPoint(0, tileSize),
new SKColor[] { SKColors.Silver, SKColors.Black },
new float[] { 0.4f, 0.6f },
SKShaderTileMode.Clamp);
canvas.DrawLine(0, tileSize / 2,
tileSize / 2, tileSize / 2 - wireThickness / 2, paint);
canvas.DrawLine(tileSize, tileSize / 2,
tileSize / 2, tileSize / 2 + wireThickness / 2, paint);
// Draw curved wires
using (SKPath path = new SKPath())
{
path.MoveTo(tileSize / 2, 0);
path.LineTo(tileSize / 2 - wireThickness / 2, tileSize / 2);
path.ArcTo(wireThickness / 2, wireThickness / 2,
0,
SKPathArcSize.Small,
SKPathDirection.CounterClockwise,
tileSize / 2, tileSize / 2 + wireThickness / 2);
paint.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0),
new SKPoint(0, tileSize),
new SKColor[] { SKColors.Silver, SKColors.Black },
null,
SKShaderTileMode.Clamp);
canvas.DrawPath(path, paint);
path.Reset();
path.MoveTo(tileSize / 2, tileSize);
path.LineTo(tileSize / 2 + wireThickness / 2, tileSize / 2);
path.ArcTo(wireThickness / 2, wireThickness / 2,
0,
SKPathArcSize.Small,
SKPathDirection.CounterClockwise,
tileSize / 2, tileSize / 2 - wireThickness / 2);
paint.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0),
new SKPoint(0, tileSize),
new SKColor[] { SKColors.White, SKColors.Silver },
null,
SKShaderTileMode.Clamp);
canvas.DrawPath(path, paint);
}
return tileBitmap;
}
}
···
}
Kablolar dışında kutucuk saydamdır ve başka bir şeyin üzerinde görüntüleyebileceğiniz anlamına gelir. Program bit eşlem kaynaklarından birine yüklenir, tuvali doldurmak için görüntüler ve gölgelendiriciyi üzerine çizer:
public class ChainLinkFencePage : ContentPage
{
SKBitmap monkeyBitmap = BitmapExtensions.LoadBitmapResource(
typeof(ChainLinkFencePage), "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg");
···
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.DrawBitmap(monkeyBitmap, info.Rect, BitmapStretch.UniformToFill,
BitmapAlignment.Center, BitmapAlignment.Start);
using (SKPaint paint = new SKPaint())
{
paint.Shader = SKShader.CreateBitmap(tileBitmap,
SKShaderTileMode.Repeat,
SKShaderTileMode.Repeat,
SKMatrix.MakeRotationDegrees(45));
canvas.DrawRect(info.Rect, paint);
}
}
}
Gölgelendiricinin 45 derece döndürüldüğünü, bu nedenle gerçek bir zincir bağlantı çiti gibi yönlendirildiğini görebilirsiniz:
Bit eşlem kutucuklarını animasyon ekleme
Matris dönüşümüne animasyon uygulayarak bit eşlem kutucuğu deseninin tamamına animasyon uygulayabilirsiniz. Belki de desenin yatay veya dikey olarak ya da her ikisini birden hareket etmesini istiyorsunuz. Bunu yapmak için, kaydırma koordinatlarını temel alan bir çeviri dönüşümü oluşturabilirsiniz.
Küçük bir bit eşlem üzerinde çizim yapmak veya bit eşlem piksel bitlerini saniyede 60 kez işlemek de mümkündür. Bu bit eşlem daha sonra döşeme için kullanılabilir ve kutucuklu desenin tamamı animasyonlu gibi görünebilir.
Animasyonlu Bit Eşlem Kutucuğu sayfası bu yaklaşımı gösterir. Bit eşlem, 64 piksel kare olacak şekilde bir alan olarak oluşturulur. Oluşturucu, ilk görünümü vermek için çağırır DrawBitmap
. angle
Alan sıfırsa (yöntem ilk çağrıldığında olduğu gibi), bit eşlem X olarak çapraz iki çizgi içerir. Çizgiler, değerden bağımsız olarak angle
bit eşlem kenarına her zaman ulaşacak kadar uzun yapılır:
public class AnimatedBitmapTilePage : ContentPage
{
const int SIZE = 64;
SKCanvasView canvasView;
SKBitmap bitmap = new SKBitmap(SIZE, SIZE);
float angle;
···
public AnimatedBitmapTilePage ()
{
Title = "Animated Bitmap Tile";
// Initialize bitmap prior to animation
DrawBitmap();
// Create SKCanvasView
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
···
void DrawBitmap()
{
using (SKCanvas canvas = new SKCanvas(bitmap))
using (SKPaint paint = new SKPaint())
{
paint.Style = SKPaintStyle.Stroke;
paint.Color = SKColors.Blue;
paint.StrokeWidth = SIZE / 8;
canvas.Clear();
canvas.Translate(SIZE / 2, SIZE / 2);
canvas.RotateDegrees(angle);
canvas.DrawLine(-SIZE, -SIZE, SIZE, SIZE, paint);
canvas.DrawLine(-SIZE, SIZE, SIZE, -SIZE, paint);
}
}
···
}
Animasyon ek yükü ve OnDisappearing
geçersiz kılmalarında OnAppearing
gerçekleşir. yöntemi, OnTimerTick
bit eşlem içinde X şeklini döndürmek için her 10 saniyede bir 0 dereceden 360 dereceye kadar değere animasyon angle
uygular:
public class AnimatedBitmapTilePage : ContentPage
{
···
// For animation
bool isAnimating;
Stopwatch stopwatch = new Stopwatch();
···
protected override void OnAppearing()
{
base.OnAppearing();
isAnimating = true;
stopwatch.Start();
Device.StartTimer(TimeSpan.FromMilliseconds(16), OnTimerTick);
}
protected override void OnDisappearing()
{
base.OnDisappearing();
stopwatch.Stop();
isAnimating = false;
}
bool OnTimerTick()
{
const int duration = 10; // seconds
angle = (float)(360f * (stopwatch.Elapsed.TotalSeconds % duration) / duration);
DrawBitmap();
canvasView.InvalidateSurface();
return isAnimating;
}
···
}
X rakamının simetrisi nedeniyle bu, değeri her 2,5 saniyede bir 0 dereceden 90 dereceye döndürmeyle angle
aynıdır.
İşleyici PaintSurface
bit eşlemden bir gölgelendirici oluşturur ve tuvalin tamamını renklendirmek için paint nesnesini kullanır:
public class AnimatedBitmapTilePage : ContentPage
{
···
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
paint.Shader = SKShader.CreateBitmap(bitmap,
SKShaderTileMode.Mirror,
SKShaderTileMode.Mirror);
canvas.DrawRect(info.Rect, paint);
}
}
}
Seçenekler, SKShaderTileMode.Mirror
basit animasyonun önerdiğinden çok daha karmaşık görünen genel bir animasyon deseni oluşturmak için her bit eşlemdeki X'in kollarının bitişik bit eşlemlerde X ile birleştirilmesini sağlar: