Skip to content

Commit

Permalink
add things
Browse files Browse the repository at this point in the history
  • Loading branch information
T-Dynamos committed Feb 27, 2024
1 parent d54300b commit 00b6616
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 4 deletions.
101 changes: 97 additions & 4 deletions kivymd/uix/scrollview.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,93 @@

__all__ = ("MDScrollView",)

import math
from kivy.effects.scroll import ScrollEffect
from kivy.uix.scrollview import ScrollView
from kivy.properties import NumericProperty, ListProperty
from kivy.graphics import Scale, PushMatrix, PopMatrix
from kivy.animation import Animation

from kivymd.uix.behaviors import DeclarativeBehavior, BackgroundColorBehavior


class MDScrollViewEffect(ScrollEffect):
class StretchOverScrollStencil(ScrollEffect):
"""
Material Design overscorll effect.
If you need any documentation please look at
:class:`~kivy.effects.dampedscrolleffect`.
"""

MAXIMUM_STRETCH = 1.07

# Android constants
minimum_absorbed_velocity = 100
maximum_velocity = 10000
stretch_intensity = 0.016
exponential_scalar = math.e / 0.33
scroll_friction = 0.015

# Velocity normilzer
normlizer = 4.5e5

scroll_view = None
scroll_scale = None

def clamp(self, value, min_val=0, max_val=0):
return min(max(value, min_val), max_val)

def __init__(self, *arg, **kwargs):
super().__init__(*arg, **kwargs)
self.friction = self.scroll_friction

def on_value(self, stencil, scroll_distance):
super().on_value(stencil, scroll_distance)
if self.target_widget:
if not all([self.scroll_view, self.scroll_scale]):
self.scroll_view = self.target_widget.parent
self.scroll_scale = self.scroll_view._internal_scale
self.apply_transform()

def set_scale_origin(self):
self.scroll_scale.origin = [
0 if self.scroll_view.scroll_x <= 0.5 else self.scroll_view.width,
0 if self.scroll_view.scroll_y <= 0.5 else self.scroll_view.height,
]

def absorb_impact(self):
sanitized_velocity = self.clamp(
abs(self.velocity), 1, self.maximum_velocity
)
new_scale = self.scroll_scale.y + sanitized_velocity / (self.normlizer)
if new_scale <= 1:
return

init_anim = Animation(
y=new_scale,
d=(sanitized_velocity * 2) / 1e6,
t="in_out_circ",
)
init_anim.bind(
on_complete=lambda *_: Animation(y=1, d=0.2, t="in_out_circ").start(
self.scroll_scale
)
)
init_anim.start(self.scroll_scale)

def on_overscroll(self, widget, value):
if self.scroll_scale and abs(value) > 0.0 and self.velocity == 0:
self.scroll_scale.y = 1 + self.stretch_intensity * (
1 - math.exp(-abs(value) * self.exponential_scalar)
)

def apply_transform(self):
if self.scroll_view.scroll_y in [1, 0]:
self.set_scale_origin()
if abs(self.velocity) > self.minimum_absorbed_velocity:
self.absorb_impact()


# class StretchOverScrollShader(ScrollEffect):
# TODO: implement it if required


class MDScrollView(DeclarativeBehavior, BackgroundColorBehavior, ScrollView):
"""
Expand All @@ -61,6 +133,27 @@ class MDScrollView(DeclarativeBehavior, BackgroundColorBehavior, ScrollView):
classes documentation.
"""

_internal_scale = None | Scale

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.effect_cls = MDScrollViewEffect
with self.canvas.before:
PushMatrix()
self._internal_scale = Scale()
with self.canvas.after:
PopMatrix()
self.effect_cls = StretchOverScrollStencil

def _normalize_scale(self):
if self._internal_scale.y > 1:
anim = Animation(y=1, d=0.1, t="in_out_circ").start(
self._internal_scale
)

def on_touch_up(self, touch):
self._normalize_scale()
super().on_touch_up(touch)

def on_touch_move(self, touch):
self._normalize_scale()
super().on_touch_move(touch)
31 changes: 31 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ./packages/flutter/lib/src/widgets/overscroll_indicator.dart
# 820
from kivy.metrics import dp
from kivy.uix.button import Button

from kivymd.app import MDApp
from kivymd.uix.scrollview import MDScrollView
from kivymd.uix.boxlayout import MDBoxLayout


class Example(MDApp):
def build(self):
scroll_view = MDScrollView()
self.main_box = MDBoxLayout(orientation="vertical")
self.main_box.adaptive_height = True
scroll_view.add_widget(self.main_box)
return scroll_view

def on_start(self):
super().on_start()
for i in range(1, 50):
self.main_box.add_widget(
Button(
text=f"Item {i}",
size_hint_y=None,
height=dp(50),
background_color=[1 if i % 2 == 0 else 0]*3 + [1],
)
)

Example().run()

0 comments on commit 00b6616

Please sign in to comment.