B4A Library Ripple Effect library

Informatix

Expert
Licensed User
I improved my version of the lib. You can find it a few posts above.
What's new: the RippleView is a view like any other B4A view, with all functions and properties, and I added the Zoom feature, which was there but not used.

The RippleView object is a panel with a single view inside. You can retrieve the embedded view with the View property.

How to use this lib:
  • If you load a layout:
    You load the layout, you create an instance of RippleView (you could do that in Globals) and you initialize this instance.
    In this example, I load a layout with a button and I apply the ripple effect on the button:
    B4X:
    Activity.LoadLayout("mylayout")
    Dim rv As RippleView
    rv.Initialize(Button1, Colors.Red, 200, True)
    If I want to apply the effect on other views of this layout, I create a new instance and call Initialize() for each view.

  • If you create your views by code:
    You can do like I explained above, after you added the view to its parent. If you cannot add the view to its parent (for example, when you pass this view to a class or library that will add it for you), you create the view, you create an instance of RippleView and you initialize this instance as usual, then you pass this instance to the class/library that will add it, instead of the view. Example:
    B4X:
    Dim Button1 As Button
    Button1.Initialize("")
    Button1.Text = "Click me"
    Dim rv As RippleView
    rv.Initialize(Button1, Colors.Red, 200, True)
    DialogCreator(rv) 'Here, I pass my RippleView, not the Button
    That works fine with BetterDialogs, for example.
 
Last edited:

ivan.tellez

Active Member
Licensed User
I improved my version of the lib. You can find it a few posts above.
What's new: the RippleView is a view like any other B4A view, with all functions and properties, and I added the Zoom feature, which was there but not used.

Wow, this is awesome :D

It is possible to modify the ripple settings After Initializing the object?

Something like this:

B4X:
Sub Globals
    Dim rv As RippleView
    Private Button1 As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    rv.Initialize(Button1, Colors.Green, 500, False)
    rv.Zoom(175, 0.9)
End Sub

Sub Button1_Click
    rv.Modify(Button1, Colors.Red, 500, False)
    rv.ModifyZoom(0, 0.9) 'Disable zoom
End Sub
If yes, could you add to your lib?

Thanks




Edit:

This is easy, also will be grat to have a:
Initialize2(View, Color, Duration, Centered, ZoomDuration, ZoomScale)
 

thedesolatesoul

Expert
Licensed User
So I thought I should post my version of the RippleView port.
Feel free to jd-gui the code, I didnt have time to test it (on its own).

The reason I rewrote it:
- I wasnt 100% satisfied with Erel's implementation, Informatix was closer to what I wanted but still not quite.
- The RippleView.java file was modified in a way that it broke compatibility with any Java lib that depends on this lib, so I had to rewrite it anyway.

So this is an export from a larger project but I wanted to demonstrate how it should work when building a view hierarchy.

Normally to put a button 'b' on a panel 'spanel' :
B4X:
    spanel.AddView(b,  10dip,200dip, 100%x - 20dip, 48dip)
Now trying to add a Ripple, with Informatix's/Erel's port:
B4X:
spanel.AddView(b,  10dip,200dip, 100%x - 20dip, 48dip)
Dim rv As RippleView
rv.Initialize(b, Colors.Red, 200, True)
Now looking at this code it is not really apparent what happened, unless you *know* what happens in the library.
The view hierarchy is not apparent at all, i.e. the parent of b is now rv, and the parent of rv is spanel.

So what I did was to add a Panel in the RippleView and use that to add the views
While this may be fraught with problems, as the panel can have multiple views (in this case it is supposed to have only one)
The code looks like this:
B4X:
    Dim rv As MSMaterialRipple
    rv.Initialize
    spanel.AddView(rv,  10dip,200dip, 100%x - 20dip, 48dip)
    rv.Panel.AddView(b, 0dip,0dip, r.Width, r.Height)
    rv.SetDuration(50)
    rv.SetupChildViewEvents(b)
So the view hierarchy is immediately apparent, i.e. rv is added to spanel, b is added to rv.

Issues with this implementation:
- Is there slowness due to adding another view layer on top? I dont know, maybe.
- The ChildView is now a view inside the panel, so I was not receiving touch and click events on it. I had to add another method to re-setup the childview so it can receive events. Why another method? Because I could not afford to break the original code, as the same implementation needs to work even when NOT using a panel. So you need to call SetupChildViewEvents before your view can receive events.
 

Attachments

Informatix

Expert
Licensed User
Wow, this is awesome :D

It is possible to modify the ripple settings After Initializing the object?

Something like this:

B4X:
Sub Globals
    Dim rv As RippleView
    Private Button1 As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    rv.Initialize(Button1, Colors.Green, 500, False)
    rv.Zoom(175, 0.9)
End Sub

Sub Button1_Click
    rv.Modify(Button1, Colors.Red, 500, False)
    rv.ModifyZoom(0, 0.9) 'Disable zoom
End Sub
If yes, could you add to your lib?

Thanks




Edit:

This is easy, also will be grat to have a:
Initialize2(View, Color, Duration, Centered, ZoomDuration, ZoomScale)
I added a Ripple function that allows to change the settings and includes two new settings: Type (simple or double) and Padding.
It's probably my last version because this object is very strange to me. From scratch, I would have not designed it this way.
 

Informatix

Expert
Licensed User
Do you mean the ripple itself or the view structure?
I would not have created this object as a Panel. It's too cumbersome to use. A simple click interceptor would have had my preference. But maybe there are too much troubles to draw the effect over the view with another solution. So my comment is based on a feeling, not on a very clear idea.
 

thedesolatesoul

Expert
Licensed User
I would not have created this object as a Panel. It's too cumbersome to use. A simple click interceptor would have had my preference. But maybe there are too much troubles to draw the effect over the view with another solution. So my comment is based on a feeling, not on a very clear idea.
For pre-L devices you would need to override the draw method of the view itself. For a Button that would probably mean extending Button, override draw, and re-wrapping it in TextViewWrapper. That would be more work to be done for every view to be wrapped.
 

Informatix

Expert
Licensed User
For pre-L devices you would need to override the draw method of the view itself. For a Button that would probably mean extending Button, override draw, and re-wrapping it in TextViewWrapper. That would be more work to be done for every view to be wrapped.
You can create a drawing surface over the view like I do with my Accelerated Surface lib. No need for a specific implementation. You just need to know X,Y,Width,Height.
 

thedesolatesoul

Expert
Licensed User
That is actually a very good idea. We can just overlay the Button(or whichever view) with an AS, and in Button_Touch call DrawRipple.
However, again the problem will be how to acheive coding elegance with this. Assuming we put the AS in a class and call RippleClass.Initialize(myButton), we need to delegate the touch event from the button parent to the class sub. Alternatively, if we create the button inside the class, then we hide all its events inside the class and have to raise them again.
 

Informatix

Expert
Licensed User
That is actually a very good idea. We can just overlay the Button(or whichever view) with an AS, and in Button_Touch call DrawRipple.
However, again the problem will be how to acheive coding elegance with this. Assuming we put the AS in a class and call RippleClass.Initialize(myButton), we need to delegate the touch event from the button parent to the class sub. Alternatively, if we create the button inside the class, then we hide all its events inside the class and have to raise them again.
If it's a standard view, you can set another listener to receive its touch events. It's what GestureDetector does.
 

incendio

Well-Known Member
Licensed User
Hi all,

I want to apply this effect on button. But when users clicked it, the ripple show its effect to fast and not noticeable caused it is continued execution codes on Button_click.

Is it possible to delay execution until the effect is finished? (Changed in durations didn't have an effect)

Thanks in advance.
 
Last edited:

incendio

Well-Known Member
Licensed User
Yes it works in asynchronous mode, but it make the effect not noticeable to users, cause execution on button click execute instanlty.

It is not possible to wait until the effect is finished (so user will noticeable the effect, just like if I set PressedDrawable in the designer) than execute the code on button click, isn't it?
 
Last edited:

Informatix

Expert
Licensed User
Yes it works in asynchronous mode, but it make the effect not noticeable to users, cause execution on button click execute instanlty.

It is not possible to wait until the effect is finished (so user will noticeable the effect, just like if I set PressedDrawable in the designer) than execute the code on button click, isn't it?
The question is: do the users want to see the effect or perform the operation as quickly as possible? When I click on a button, I want to perform an action (open an activity, close a dialog, validate an input, etc.). I didn't click on the button to see an animation.
 

thedesolatesoul

Expert
Licensed User
It is not possible to wait until the effect is finished (so user will noticeable the effect, just like if I set PressedDrawable in the designer) than execute the code on button click, isn't it?
I have a version of this that starts the ripple on Touch_Down instead of Touch_Up. You can see the ripple before anything executes, but your finger is blocking it. I am just not too sure about this ripple effect yet. Project Polymer does it in a better way.
 

incendio

Well-Known Member
Licensed User
The question is: do the users want to see the effect or perform the operation as quickly as possible? When I click on a button, I want to perform an action (open an activity, close a dialog, validate an input, etc.). I didn't click on the button to see an animation.
It is not for animation, a few ms delay will make users noticed that he/she already pressed the button.

Somehow, when setting PressedDrawable on a button in the designer and then changed bitmap background in a code didn't work for me.

Before I found out what's going wrong, I saw this library, and thought, this could be a simple solution, but seem I was wrong.

I guest, I will try to stick with PressedDrawable.
 

airblaster

Active Member
Licensed User
This library is useful, but I noticed a difference to Google's version:
Google's Ripple effect already starts while you press a button.
This library on the other hand starts the ripple only after a Click occured, and only if it isn't a LongClick.
Or was this fixed in any of the subsequent versions of the library that were posted here?
 

derez

Expert
Licensed User
Ripple Effect should start before the user press the button, showing him which button he should press ...
 
Top