animate grid card overlay
This commit is contained in:
+97
-16
@@ -1,9 +1,12 @@
|
||||
package widgets
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
@@ -35,20 +38,29 @@ type coverImage struct {
|
||||
OnShowPage func()
|
||||
OnShowContextMenu func(fyne.Position)
|
||||
|
||||
Im *ImagePlaceholder
|
||||
playbtn *canvas.Image
|
||||
favoriteButton *canvas.Image
|
||||
moreButton *canvas.Image
|
||||
prevTheme fyne.ThemeVariant
|
||||
bottomPanel *fyne.Container
|
||||
Im *ImagePlaceholder
|
||||
playbtn *canvas.Image
|
||||
favoriteButton *canvas.Image
|
||||
moreButton *canvas.Image
|
||||
gradient *canvas.LinearGradient
|
||||
bottomPanel *fyne.Container
|
||||
|
||||
mouseInAnim *fyne.Animation
|
||||
|
||||
mouseInsidePlay bool
|
||||
mouseInsideFav bool
|
||||
mouseInsideMore bool
|
||||
}
|
||||
|
||||
var (
|
||||
playBtnSize = fyne.NewSize(60, 60)
|
||||
playBtnHoveredSize = fyne.NewSize(65, 65)
|
||||
// N.B: Only one GridViewItem can be showing the play image
|
||||
// at a time, so they can share this image.Image
|
||||
playBtnImageSrc, playBtnImage image.Image
|
||||
|
||||
// opacity when unhovered
|
||||
playBtnOpacity = float32(0.85)
|
||||
playBtnSize = fyne.NewSquareSize(60)
|
||||
playBtnHoveredSize = fyne.NewSquareSize(70)
|
||||
|
||||
resourcesInitted bool
|
||||
heartFilledResource fyne.Resource
|
||||
@@ -66,6 +78,9 @@ func initResources() {
|
||||
}
|
||||
resourcesInitted = true
|
||||
|
||||
playBtnImageSrc, _ = png.Decode(bytes.NewReader(res.ResPlaybuttonPng.StaticContent))
|
||||
playBtnImage = image.NewNRGBA(playBtnImageSrc.Bounds())
|
||||
|
||||
inlineIconSize = fyne.CurrentApp().Settings().Theme().Size(theme.SizeNameInlineIcon)
|
||||
|
||||
// TODO: replace util.ColorizeSVG with Fyne's canvas.ColorizeSVG once
|
||||
@@ -91,16 +106,18 @@ func newCoverImage(placeholderResource fyne.Resource) *coverImage {
|
||||
c.Im.OnTapped = c.Tapped
|
||||
c.Im.OnTappedSecondary = c.TappedSecondary
|
||||
c.Im.ScaleMode = canvas.ImageScaleFastest
|
||||
c.playbtn = &canvas.Image{FillMode: canvas.ImageFillContain, Resource: res.ResPlaybuttonPng}
|
||||
c.playbtn = &canvas.Image{FillMode: canvas.ImageFillContain, Image: playBtnImage}
|
||||
c.playbtn.SetMinSize(playBtnSize)
|
||||
c.playbtn.ScaleMode = canvas.ImageScaleFastest
|
||||
c.playbtn.Hidden = true
|
||||
|
||||
c.favoriteButton = canvas.NewImageFromResource(heartUnfilledResource)
|
||||
c.favoriteButton.SetMinSize(fyne.NewSquareSize(inlineIconSize))
|
||||
c.moreButton = canvas.NewImageFromResource(moreVerticalResource)
|
||||
c.moreButton.SetMinSize(fyne.NewSquareSize(inlineIconSize))
|
||||
c.gradient = canvas.NewVerticalGradient(color.Transparent, color.Black)
|
||||
c.bottomPanel = container.NewStack(
|
||||
canvas.NewVerticalGradient(color.Transparent, color.Black),
|
||||
c.gradient,
|
||||
container.NewVBox(
|
||||
layout.NewSpacer(), // keep the HBox pushed down
|
||||
container.NewHBox(
|
||||
@@ -165,14 +182,44 @@ func (c *coverImage) TappedSecondary(e *fyne.PointEvent) {
|
||||
}
|
||||
|
||||
func (a *coverImage) MouseIn(*desktop.MouseEvent) {
|
||||
a.playbtn.Hidden = false
|
||||
a.updateFavoriteIcon(false)
|
||||
a.favoriteButton.Hidden = !a.EnableFavorite
|
||||
a.bottomPanel.Hidden = false
|
||||
a.Refresh()
|
||||
|
||||
firstTick := true
|
||||
a.mouseInAnim = fyne.NewAnimation(225*time.Millisecond, func(f float32) {
|
||||
a.playbtn.Hidden = false
|
||||
a.favoriteButton.Hidden = !a.EnableFavorite
|
||||
a.bottomPanel.Hidden = false
|
||||
|
||||
if !a.mouseInsidePlay {
|
||||
setPlayBtnTranslucency(f * float32(playBtnOpacity))
|
||||
// else being controlled by other animation
|
||||
}
|
||||
|
||||
t := float64(1 - f)
|
||||
a.moreButton.Translucency = t
|
||||
a.favoriteButton.Translucency = t
|
||||
a.gradient.EndColor = color.RGBA{A: uint8(f * 255)}
|
||||
|
||||
if firstTick {
|
||||
firstTick = false
|
||||
a.Refresh()
|
||||
} else {
|
||||
a.playbtn.Refresh()
|
||||
a.bottomPanel.Refresh()
|
||||
}
|
||||
if f == 1 {
|
||||
a.mouseInAnim = nil
|
||||
}
|
||||
})
|
||||
a.mouseInAnim.Curve = fyne.AnimationEaseIn
|
||||
a.mouseInAnim.Start()
|
||||
}
|
||||
|
||||
func (a *coverImage) MouseOut() {
|
||||
if a.mouseInAnim != nil {
|
||||
a.mouseInAnim.Stop()
|
||||
a.mouseInAnim = nil
|
||||
}
|
||||
a.mouseInsidePlay = false
|
||||
a.mouseInsideFav = false
|
||||
a.mouseInsideMore = false
|
||||
@@ -187,9 +234,21 @@ func (a *coverImage) MouseMoved(e *desktop.MouseEvent) {
|
||||
return
|
||||
}
|
||||
if in {
|
||||
a.playbtn.SetMinSize(playBtnHoveredSize)
|
||||
fyne.NewAnimation(canvas.DurationShort, func(f float32) {
|
||||
t := (1-playBtnOpacity)*f + playBtnOpacity
|
||||
setPlayBtnTranslucency(t)
|
||||
delta := playBtnHoveredSize.Subtract(playBtnSize)
|
||||
a.playbtn.SetMinSize(playBtnSize.Add(fyne.NewSquareSize(delta.Width * f)))
|
||||
a.playbtn.Refresh()
|
||||
}).Start()
|
||||
} else {
|
||||
a.playbtn.SetMinSize(playBtnSize)
|
||||
fyne.NewAnimation(canvas.DurationShort, func(f float32) {
|
||||
t := 1 - (1-playBtnOpacity)*f
|
||||
setPlayBtnTranslucency(t)
|
||||
delta := playBtnHoveredSize.Subtract(playBtnSize)
|
||||
a.playbtn.SetMinSize(playBtnHoveredSize.Subtract(fyne.NewSquareSize(delta.Height * f)))
|
||||
a.playbtn.Refresh()
|
||||
}).Start()
|
||||
}
|
||||
a.playbtn.Refresh()
|
||||
a.mouseInsidePlay = in
|
||||
@@ -282,6 +341,28 @@ func isInside(origin fyne.Position, radius float32, point fyne.Position) bool {
|
||||
return x*x+y*y <= radius*radius
|
||||
}
|
||||
|
||||
func setPlayBtnTranslucency(f float32) {
|
||||
size := playBtnImageSrc.Bounds().Size()
|
||||
primary := theme.Color(theme.ColorNamePrimary).(color.NRGBA)
|
||||
for x := 0; x < size.X; x++ {
|
||||
for y := 0; y < size.Y; y++ {
|
||||
r, _, _, a := playBtnImageSrc.At(x, y).RGBA()
|
||||
// using the PNG source just as an alpha mask + white play triangle
|
||||
c := primary
|
||||
if r > 65000 {
|
||||
// pixel is white (play triangle)
|
||||
c = color.NRGBA{
|
||||
R: 255,
|
||||
G: 255,
|
||||
B: 255,
|
||||
}
|
||||
}
|
||||
c.A = uint8(float32(a) / 257 * f)
|
||||
playBtnImage.(*image.NRGBA).SetNRGBA(x, y, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type GridViewItemModel struct {
|
||||
Name string
|
||||
ID string
|
||||
|
||||
Reference in New Issue
Block a user