为了账号安全,请及时绑定邮箱和手机立即绑定

如何在缩放时更新Scatter中嵌入的RecycleView的数据值(即图像宽度,高度)?

如何在缩放时更新Scatter中嵌入的RecycleView的数据值(即图像宽度,高度)?

慕码人8056858 2022-12-20 11:07:12
找不到有关嵌入在 Scatter 小部件中的 RecycleView 的任何详细信息。尽管在 RecycleView(或一般的 ScrollView)嵌入 Scatter 的情况下有几个与触摸相关的问题,但在我的特定情况下,问题是在缩放图像时图像宽度/高度等属性没有改变(Scatter 的预期行为),因此 RecycleView 布局不会更新。因此,水平滚动是不可能的。请查看以下代码:from kivy.app import Appfrom kivy.uix.image import Imagefrom kivy.uix.recycleview import RecycleViewfrom kivy.core.window import Windowfrom kivy.uix.scatter import Scatterfrom kivy.uix.floatlayout import FloatLayoutfrom kivy.lang import Builderfrom kivy.metrics import sp, dpfrom kivy.animation import Animationfrom kivy.uix.widget import Widgetfrom PIL import Image as PILImageMY_APP_KV_LANG = """#:import ScrollEffect kivy.effects.scroll.ScrollEffect<RootLayout>:    size_hint: 1, 1    canvas.before:        Color:            rgba: (0, 0, 0, 1)        Rectangle:            size: self.size            pos: self.pos            DocLayoutScat:        id: docscat        DocumentWidget:            id: rv            viewclass: 'Image'            key_size: 'size'            effect_cls: ScrollEffect            scroll_type: ['content']            bar_width: 0            cols: 1            width: docscat.width            height: docscat.height            RecycleBoxLayout:                id: rvbox                spacing: dp(10)                padding: dp(10)                cols: rv.cols                orientation: 'vertical'                size_hint: None, None                height: self.minimum_height                width: self.minimum_width                default_size_hint: 1, None"""我试图用比例值改变图像的宽度/高度,但这会使增加宽度/高度的效果加倍。有什么方法可以更新 RecycleView 的数据属性以及缩放,以便在缩放/缩放时可以水平滚动?
查看完整描述

1 回答

?
动漫人物

TA贡献1815条经验 获得超10个赞

找到了在不添加散点小部件的情况下实现捏合缩放的方法,因为散点不会更新数据的宽度和高度,因此滚动尺寸也不会更新。下面是没有分散的实现。缩放适用于触摸锚点。这并不理想,因为动画不流畅。


from kivy.app import App

from kivy.uix.image import Image

from kivy.uix.recycleview import RecycleView

from kivy.core.window import Window

from kivy.uix.floatlayout import FloatLayout

from kivy.lang import Builder

from kivy.metrics import sp, dp

from kivy.animation import Animation

from kivy.uix.widget import Widget

from PIL import Image as PILImage

from kivy.properties import NumericProperty

from kivy.graphics.transformation import Matrix

from kivy.vector import Vector

from kivy.graphics.context_instructions import PopMatrix, PushMatrix, Translate


MY_APP_KV_LANG = """

#:import ScrollEffect kivy.effects.scroll.ScrollEffect

<RootLayout>:

    size_hint: 1, 1

    canvas.before:

        Color:

            rgba: (0, 0, 0, 1)

        Rectangle:

            size: self.size

            pos: self.pos        

    DocumentWidget:

        id: rv

        viewclass: 'Image'

        key_size: 'size'

        effect_cls: ScrollEffect

        scroll_type: ['content']

        bar_width: 0

        cols: 1

        RecycleBoxLayout:

            id: rvbox

            spacing: dp(10)

            padding: dp(10)

            cols: rv.cols

            orientation: 'vertical'

            size_hint: None, None

            height: self.minimum_height

            width: self.minimum_width

            default_size_hint: 1, None

"""


class RootLayout(FloatLayout):

    pass


class DocumentWidget(RecycleView):

    scale = NumericProperty(1.)

    scroll_y1 = NumericProperty(0.)

    scroll_y2 = NumericProperty(0.)

    delta_scy = NumericProperty(0.)

    def __init__(self, **kwargs):

        super(DocumentWidget, self).__init__(**kwargs)

        pil_image = PILImage.open('test3.jpg')

        self.data = [{'source': 'test3.jpg', 'width': Window.size[0] - dp(20), 'height': (Window.size[0] - dp(20)) * pil_image.size[1] / pil_image.size[0], 'size_hint_x': None, 'size_hint_y': None, 'allow_stretch': True, 'keep_ratio': True} for x in range(3)]

        self.data_initial = [{'width': Window.size[0] - dp(20), 'height': (Window.size[0] - dp(20)) * pil_image.size[1] / pil_image.size[0]} for x in range(3)]

        self.bind(on_scale = self.on_scale)


    def on_touch_up(self, touch):

        if self.collide_point(*touch.pos):

            if touch.is_double_tap:

                if 1.0 >= self.scale >= 0.99: 

                    self.scroll_y1 = self.scroll_y

                    self.delta_scy = Window.size[1] - touch.pos[1] - dp(10)

                    def _prg(*args):

                        self.scroll_x = (touch.pos[0] * self.scale) / (self.data[0]["width"] + dp(20))

                        self.scroll_y = self.scroll_y1 - self.scroll_y1 * self.delta_scy * (self.scale - 1) / (self.layout_manager.size[1] - Window.size[1])                    

                        self.scroll_y2 = self.scroll_y

                    anim = Animation(scale=2, duration=0.2, transition='in_quad')

                    anim.bind(on_progress=_prg)

                    anim.start(self)

                else:

                    def _prg(*args):

                        self.scroll_y = (self.scroll_y2 - self.scroll_y1) * self.scale + 2 * self.scroll_y1 - self.scroll_y2 

                    anim = Animation(scale=1, duration=0.2, transition='out_quad')

                    anim.bind(on_progress=_prg)

                    anim.start(self)

        return super(DocumentWidget, self).on_touch_up(touch)


    def on_scale(self, *args):

        for x in range(3): 

            self.data[x]["height"] = self.data_initial[x]["height"] * self.scale

            self.data[x]["width"] = self.data_initial[x]["width"] * self.scale

        self.refresh_from_data()


class MyApp(App):

    def build(self):

        self.root = Builder.load_string(MY_APP_KV_LANG)

        return RootLayout()


if __name__ == "__main__":

    MyApp().run()



查看完整回答
反对 回复 2022-12-20
  • 1 回答
  • 0 关注
  • 72 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信