admin管理员组

文章数量:1430747

I am creating Roku channel. In my logic, there is an array of media(image&video), and I am displaying them with their timeout seconds. For example, one image is displaying 5 secs, then goes to next one. I have fading animation when going to next image. But I also need to add sliding animation. This is my code:

xml:

<component name="RendererScreen"
           extends="Group">
    <script type="text/brightscript"
            uri="RendererScreen.bs" />
    <children>
        <Poster id="backgroundImg"
                width="1920"
                height="1080"
                uri="pkg:/images/background.png" />
        <Poster id="imgPoster"
                width="1920"
                height="1080"
                translation="[0, 0]"
                opacity="0.0"
                visible="true" />
        <Animation id="fadeInAnimation"
                   repeat="false"
                   control="stop"
                   easeFunction="linear">
            <FloatFieldInterpolator id="fadeInInterpolator"
                                    key="[0.0, 1.0]"
                                    keyValue="[0.0, 1.0]"
                                    fieldToInterp="imgPoster.opacity" />
        </Animation>
        <Animation id="fadeOutAnimation"
                   repeat="false"
                   control="stop"
                   easeFunction="linear">
            <FloatFieldInterpolator id="fadeOutInterpolator"
                                    key="[0.0, 1.0]"
                                    keyValue="[1.0, 0.0]"
                                    fieldToInterp="imgPoster.opacity" />
        </Animation>
        <Animation id="slideInAnimation"
                   repeat="false"
                   control="stop"
                   easeFunction="linear">
            <FloatFieldInterpolator id="slideInInterpolator"
                                    key="[0.0, 1.0]"
                                    keyValue="[0.0, 1.0]"
                                    fieldToInterp="imgPoster.translation" />
        </Animation>
        <Animation id="slideOutAnimation"
                   repeat="false"
                   control="stop"
                   easeFunction="linear">
            <FloatFieldInterpolator id="slideOutInterpolator"
                                    key="[0.0, 1.0]"
                                    keyValue="[0.0, 1.0]"
                                    fieldToInterp="imgPoster.translation" />
        </Animation>
        <Video id="videoPlayer"
               width="1920"
               height="1080"
               translation="[0, 0]"
               visible="false" />
    </children>
</component>

bs file:

sub init()
    m.poster = m.top.findNode("imgPoster")
    m.backgroundImg = m.top.findNode("backgroundImg")
    m.mediaList = []
    m.currentIndex = 0
    m.deviceOrientation = "90"

    fetchPlaylistData()
end sub

sub showMedia()
    if (m.mediaList.count() = 0)
        return
    end if

    mediaItem = m.mediaList[m.currentIndex]
    mediaType = mediaItem.type
    mediaUrl = mediaItem.url
    timeoutSeconds = mediaItem.timeoutSeconds

    m.backgroundImg.visible = false

    animationDuration = 1
    fadeInAnimation = m.top.findNode("fadeInAnimation")
    fadeOutAnimation = m.top.findNode("fadeOutAnimation")
    fadeInAnimation.duration = animationDuration
    fadeOutAnimation.duration = animationDuration

    ' I need to add here if clause(if animation is fade or slide)

    if (mediaType = "image")
        fadeInAnimation.control = "start"
        displayImage(mediaUrl)
    else if (mediaType = "video")
        displayVideo(mediaUrl)
    end if

    startSlideShowTimer(timeoutSeconds)
end sub

sub displayVideo(url as string)
    if (m.videoPlayer = invalid)
        m.videoPlayer = m.top.findNode("videoPlayer")
        m.videoPlayer.observeField("state", "onVideoStateChange")
    end if

    if (m.videoPlayer <> invalid)
        videoContent = createObject("roSGNode", "ContentNode")
        videoContent.url = url
        m.videoPlayer.content = videoContent
        m.videoPlayer.visible = true
        m.videoPlayer.control = "play"
    else
        print "Error: Video node not found."
    end if
end sub

sub onVideoStateChange()
    if (m.videoPlayer.state = "error")
        m.videoPlayer.control = "stop"
        m.videoPlayer.visible = false
        startErrorDelayTimer() 
    end if
end sub

sub displayImage(url as string)
    if (m.poster <> invalid)
        if(m.deviceOrientation = "90")
            m.poster.width = "1080"
            m.poster.height = "1920"
            m.poster.translation = [420, -420]
            m.poster.rotation = -1.570795 ' -> 3.14159/2 = π/2
        else if(m.deviceOrientation = "180")
            m.poster.width = "1920"
            m.poster.height = "1080"
            m.poster.translation = [0, 0]
            m.poster.rotation = 3.14159 ' -> π
        else if(m.deviceOrientation = "270")
            m.poster.width = "1080"
            m.poster.height = "1920"
            m.poster.translation = [420, -420]
            m.poster.rotation = 1.570795 ' -> 3.14159/2 = π/2
        end if

        m.poster.scaleRotateCenter = [m.poster.width / 2, m.poster.height / 2]
        m.poster.uri = url
        m.poster.observeField("loadStatus", "onPosterStateChange")
        m.poster.visible = true
    else
        print "Error: Poster node not found."
    end if
end sub

sub onPosterStateChange()
    if (m.poster.loadStatus = "failed")
        m.poster.visible = false
        startErrorDelayTimer()
    end if
end sub

sub startErrorDelayTimer()
    if (m.errorDelayTimer = invalid)
        m.errorDelayTimer = createObject("roSGNode", "Timer")
        m.errorDelayTimer.observeField("fire", "onErrorDelayComplete")
        m.top.appendChild(m.errorDelayTimer)
    end if

    m.errorDelayTimer.duration = 3
    m.errorDelayTimer.repeat = false
    m.errorDelayTimer.control = "start"
end sub

sub onErrorDelayComplete()    
    m.currentIndex = (m.currentIndex + 1) mod m.mediaList.count()
    showMedia()
end sub

sub startSlideShowTimer(duration as integer)
    if (m.timer = invalid)
        m.timer = createObject("roSGNode", "Timer")
        m.timer.observeField("fire", "onTimerFired")
        m.top.appendChild(m.timer)
    end if

    m.timer.duration = duration
    m.timer.repeat = false
    m.timer.control = "start"
end sub

sub onTimerFired()
    fadeOutAnimation = m.top.findNode("fadeOutAnimation")
    fadeOutAnimation.observeField("completion", "onFadeOutComplete")
    fadeOutAnimation.control = "start"

    startOutTimer(fadeOutAnimation.duration)
end sub

sub startOutTimer(animationDuration as integer)
    if (m.animationTimer = invalid)
        m.animationTimer = createObject("roSGNode", "Timer")
        m.animationTimer.observeField("fire", "onFadeOutComplete")
        m.top.appendChild(m.animationTimer)
    end if

    m.animationTimer.duration = animationDuration
    m.animationTimer.repeat = false
    m.animationTimer.control = "start"
end sub

sub onFadeOutComplete()
    if (m.videoPlayer <> invalid)
        m.videoPlayer.control = "stop"
        m.videoPlayer.visible = false
    end if

    m.currentIndex = (m.currentIndex + 1) mod m.mediaList.count()
    showMedia()
end sub

I am creating Roku channel. In my logic, there is an array of media(image&video), and I am displaying them with their timeout seconds. For example, one image is displaying 5 secs, then goes to next one. I have fading animation when going to next image. But I also need to add sliding animation. This is my code:

xml:

<component name="RendererScreen"
           extends="Group">
    <script type="text/brightscript"
            uri="RendererScreen.bs" />
    <children>
        <Poster id="backgroundImg"
                width="1920"
                height="1080"
                uri="pkg:/images/background.png" />
        <Poster id="imgPoster"
                width="1920"
                height="1080"
                translation="[0, 0]"
                opacity="0.0"
                visible="true" />
        <Animation id="fadeInAnimation"
                   repeat="false"
                   control="stop"
                   easeFunction="linear">
            <FloatFieldInterpolator id="fadeInInterpolator"
                                    key="[0.0, 1.0]"
                                    keyValue="[0.0, 1.0]"
                                    fieldToInterp="imgPoster.opacity" />
        </Animation>
        <Animation id="fadeOutAnimation"
                   repeat="false"
                   control="stop"
                   easeFunction="linear">
            <FloatFieldInterpolator id="fadeOutInterpolator"
                                    key="[0.0, 1.0]"
                                    keyValue="[1.0, 0.0]"
                                    fieldToInterp="imgPoster.opacity" />
        </Animation>
        <Animation id="slideInAnimation"
                   repeat="false"
                   control="stop"
                   easeFunction="linear">
            <FloatFieldInterpolator id="slideInInterpolator"
                                    key="[0.0, 1.0]"
                                    keyValue="[0.0, 1.0]"
                                    fieldToInterp="imgPoster.translation" />
        </Animation>
        <Animation id="slideOutAnimation"
                   repeat="false"
                   control="stop"
                   easeFunction="linear">
            <FloatFieldInterpolator id="slideOutInterpolator"
                                    key="[0.0, 1.0]"
                                    keyValue="[0.0, 1.0]"
                                    fieldToInterp="imgPoster.translation" />
        </Animation>
        <Video id="videoPlayer"
               width="1920"
               height="1080"
               translation="[0, 0]"
               visible="false" />
    </children>
</component>

bs file:

sub init()
    m.poster = m.top.findNode("imgPoster")
    m.backgroundImg = m.top.findNode("backgroundImg")
    m.mediaList = []
    m.currentIndex = 0
    m.deviceOrientation = "90"

    fetchPlaylistData()
end sub

sub showMedia()
    if (m.mediaList.count() = 0)
        return
    end if

    mediaItem = m.mediaList[m.currentIndex]
    mediaType = mediaItem.type
    mediaUrl = mediaItem.url
    timeoutSeconds = mediaItem.timeoutSeconds

    m.backgroundImg.visible = false

    animationDuration = 1
    fadeInAnimation = m.top.findNode("fadeInAnimation")
    fadeOutAnimation = m.top.findNode("fadeOutAnimation")
    fadeInAnimation.duration = animationDuration
    fadeOutAnimation.duration = animationDuration

    ' I need to add here if clause(if animation is fade or slide)

    if (mediaType = "image")
        fadeInAnimation.control = "start"
        displayImage(mediaUrl)
    else if (mediaType = "video")
        displayVideo(mediaUrl)
    end if

    startSlideShowTimer(timeoutSeconds)
end sub

sub displayVideo(url as string)
    if (m.videoPlayer = invalid)
        m.videoPlayer = m.top.findNode("videoPlayer")
        m.videoPlayer.observeField("state", "onVideoStateChange")
    end if

    if (m.videoPlayer <> invalid)
        videoContent = createObject("roSGNode", "ContentNode")
        videoContent.url = url
        m.videoPlayer.content = videoContent
        m.videoPlayer.visible = true
        m.videoPlayer.control = "play"
    else
        print "Error: Video node not found."
    end if
end sub

sub onVideoStateChange()
    if (m.videoPlayer.state = "error")
        m.videoPlayer.control = "stop"
        m.videoPlayer.visible = false
        startErrorDelayTimer() 
    end if
end sub

sub displayImage(url as string)
    if (m.poster <> invalid)
        if(m.deviceOrientation = "90")
            m.poster.width = "1080"
            m.poster.height = "1920"
            m.poster.translation = [420, -420]
            m.poster.rotation = -1.570795 ' -> 3.14159/2 = π/2
        else if(m.deviceOrientation = "180")
            m.poster.width = "1920"
            m.poster.height = "1080"
            m.poster.translation = [0, 0]
            m.poster.rotation = 3.14159 ' -> π
        else if(m.deviceOrientation = "270")
            m.poster.width = "1080"
            m.poster.height = "1920"
            m.poster.translation = [420, -420]
            m.poster.rotation = 1.570795 ' -> 3.14159/2 = π/2
        end if

        m.poster.scaleRotateCenter = [m.poster.width / 2, m.poster.height / 2]
        m.poster.uri = url
        m.poster.observeField("loadStatus", "onPosterStateChange")
        m.poster.visible = true
    else
        print "Error: Poster node not found."
    end if
end sub

sub onPosterStateChange()
    if (m.poster.loadStatus = "failed")
        m.poster.visible = false
        startErrorDelayTimer()
    end if
end sub

sub startErrorDelayTimer()
    if (m.errorDelayTimer = invalid)
        m.errorDelayTimer = createObject("roSGNode", "Timer")
        m.errorDelayTimer.observeField("fire", "onErrorDelayComplete")
        m.top.appendChild(m.errorDelayTimer)
    end if

    m.errorDelayTimer.duration = 3
    m.errorDelayTimer.repeat = false
    m.errorDelayTimer.control = "start"
end sub

sub onErrorDelayComplete()    
    m.currentIndex = (m.currentIndex + 1) mod m.mediaList.count()
    showMedia()
end sub

sub startSlideShowTimer(duration as integer)
    if (m.timer = invalid)
        m.timer = createObject("roSGNode", "Timer")
        m.timer.observeField("fire", "onTimerFired")
        m.top.appendChild(m.timer)
    end if

    m.timer.duration = duration
    m.timer.repeat = false
    m.timer.control = "start"
end sub

sub onTimerFired()
    fadeOutAnimation = m.top.findNode("fadeOutAnimation")
    fadeOutAnimation.observeField("completion", "onFadeOutComplete")
    fadeOutAnimation.control = "start"

    startOutTimer(fadeOutAnimation.duration)
end sub

sub startOutTimer(animationDuration as integer)
    if (m.animationTimer = invalid)
        m.animationTimer = createObject("roSGNode", "Timer")
        m.animationTimer.observeField("fire", "onFadeOutComplete")
        m.top.appendChild(m.animationTimer)
    end if

    m.animationTimer.duration = animationDuration
    m.animationTimer.repeat = false
    m.animationTimer.control = "start"
end sub

sub onFadeOutComplete()
    if (m.videoPlayer <> invalid)
        m.videoPlayer.control = "stop"
        m.videoPlayer.visible = false
    end if

    m.currentIndex = (m.currentIndex + 1) mod m.mediaList.count()
    showMedia()
end sub
Share Improve this question asked Nov 19, 2024 at 12:27 SuleymanSuleyman 651 silver badge3 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

To handle sliding in and out, you'll need to maintain two separate posters that you swap between. Here's an example showing how to fade between two posters. We leverage the .delay property on animation to keep the current poster visible for the timeoutSeconds in your example.

<?xml version="1.0" encoding="utf-8"?>
<component name="MainScene" extends="Scene">
  <script type="text/brightscript" uri="MainScene.brs" />

  <children>
    <Poster id="posterPrimary" width="1920" height="1080" />
    <Poster id="posterSecondary" width="1920" height="1080" />
    <!--slide and fade the secondary poster INTO view and the primary poster OUT of view, -->
    <Animation id="animationShowSecondary" repeat="false" control="stop" easeFunction="linear">
      <FloatFieldInterpolator id="fadeInInterpolator1" key="[0.0, 1.0]" keyValue="[0.0, 1.0]" fieldToInterp="posterSecondary.opacity" />
      <FloatFieldInterpolator id="fadeOutInterpolator1" key="[0.0, 1.0]" keyValue="[1.0, 0.0]" fieldToInterp="posterPrimary.opacity" />
      <Vector2DFieldInterpolator id="slideInInterpolator1" key="[0.0, 1.0]" keyValue="[[1920,0], [0,0]]" fieldToInterp="posterSecondary.translation" />
      <Vector2DFieldInterpolator id="slideOutInterpolator1" key="[0.0, 1.0]" keyValue="[[0,0], [-1920,0]]" fieldToInterp="posterPrimary.translation" />
    </Animation>
    <!--slide and fade the primary poster INTO view and the secondary poster OUT of view, -->
    <Animation id="animationShowPrimary" repeat="false" control="stop" easeFunction="linear">
      <FloatFieldInterpolator id="fadeInInterpolator2" key="[0.0, 1.0]" keyValue="[0.0, 1.0]" fieldToInterp="posterPrimary.opacity" />
      <FloatFieldInterpolator id="fadeOutInterpolator2" key="[0.0, 1.0]" keyValue="[1.0, 0.0]" fieldToInterp="posterSecondary.opacity" />
      <Vector2DFieldInterpolator id="slideInInterpolator2" key="[0.0, 1.0]" keyValue="[[1920,0], [0,0]]" fieldToInterp="posterPrimary.translation" />
      <Vector2DFieldInterpolator id="slideOutInterpolator2" key="[0.0, 1.0]" keyValue="[[0,0], [-1920,0]]" fieldToInterp="posterSecondary.translation" />
    </Animation>
  </children>
</component>
sub init()
  m.posterPrimary = m.top.findNode("posterPrimary")
  m.posterSecondary = m.top.findNode("posterSecondary")
  m.animationShowSecondary = m.top.findNode("animationShowSecondary")
  m.animationShowPrimary = m.top.findNode("animationShowPrimary")
  'anytime the animations change, we want to know about it
  m.animationShowSecondary.observeFieldScoped("state", "onanimationShowSecondaryStateChange")
  m.animationShowPrimary.observeFieldScoped("state", "onanimationShowPrimaryStateChange")

  'list of media items. This can be fetched dynamically from the server, and each one specifies how long they are visible
  m.mediaItems = [{
    uri: "pkg:/media/water.jpg",
    timeoutSeconds: 3
  }, {
    uri: "pkg:/media/bunny.jpg",
    timeoutSeconds: 5
  }]
  'show the first poster
  showImageAtIndex(m.posterSecondary, 1)
  showImageAtIndex(m.posterPrimary, 0)
  m.animationShowSecondary.delay = m.mediaItems[m.currentMediaItemIndex].timeoutSeconds
  m.animationShowSecondary.control = "start"
end sub

function showImageAtIndex(poster, mediaItemIndex as integer)
  if mediaItemIndex > m.mediaItems.count() - 1
    mediaItemIndex = 0
  end if
  mediaItem = m.mediaItems[mediaItemIndex]
  poster.uri = mediaItem.uri
  m.currentMediaItemIndex = mediaItemIndex
end function

sub onanimationShowSecondaryStateChange()
  if m.animationShowSecondary.state = "stopped"
    showImageAtIndex(m.posterPrimary, m.currentMediaItemIndex + 1)
    m.animationShowPrimary.delay = m.mediaItems[m.currentMediaItemIndex].timeoutSeconds
    m.animationShowPrimary.control = "start"
  end if
end sub

sub onanimationShowPrimaryStateChange()
  if m.animationShowPrimary.state = "stopped"
    showImageAtIndex(m.posterSecondary, m.currentMediaItemIndex + 1)
    m.animationShowSecondary.delay = m.mediaItems[m.currentMediaItemIndex].timeoutSeconds
    m.animationShowSecondary.control = "start"
  end if
end sub

本文标签: brightscriptHow to add Slide Animation to Roku39s PosterStack Overflow