Label on Android has no ripple effect
See: http://stackoverflow.com/questions/33477025/how-to-set-a-ripple-effect-on-textview-or-imageview-on-android
And: http://developer.android.com/training/material/animations.html#Touch
What i tried:
<label tap="signOutLabelTapped" text="Sign out" id="signOutLabel" />
var signOutButton = page.getViewById("signOutLabel");
// signOutButton.android.setClickable(true); // this is already done?
signOutButton.android.setBackground("?attr/selectableItemBackgroundBorderless"); // Exceptions
I really want to make something like this:
My workaround is to wrap everything in listviews :(
Android
1.6
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
To add to this issue. Currently if you are laying out a view similar to a <ListView>
via XML you lose the ripple effect on >=21 (Lollipop devices). If you create the listview layout via .js and databinding your items then the listview would have its ripple effect touching the items. I think that a layout defined in XML should have the ripple effect. Not necessarily the <Label>
as mentioned in the issue, but the container of the label.
For example:
<stack-layout>
<label text="Ripple" />
</stack-layout>
The entire stack-layout
should animate the ripple on touch. This could also be extended to any touchable view. Images, any view that is within a container and working with touch events would be great to have the ripple enabled by default and it would be awesome if an attribute was added for android to disable the ripple effect on various views. I wouldn't use it but I could see some devs wanting an attribute(boolean) like <label text="hi" rippleEffect="false" />
+1
:+1:
馃憤
+1
馃憤
+1
+1
Can someone shed more light what exactly is required in this issue?
I think @bradmartin already gave a good summary in his post above.
A layout container should animate the ripple effect on touch by default for a better user experience.
In native Android development you only need to add this to your layout or to any view:
android:clickable="true"
android:background="?attr/selectableItemBackground"
It would be great if this would be default for any clickable view container in NativeScript and only if you do not want the ripple effect, add this in your xml: ripple="false"
.
So at the end it would be much easier to get something like this:
Exactly, nice summary @felix-idf
Thanks @felix-idf,
Now i think that this should be easy enough to do it from code behind (but I haven't tested it). My guess is that getting the resource id of selectableItemBackground
and calling setBackground with it will make the view with ripple effect. But changing all views background should not come from tns-core-modules. We aim to provide default native experience but ripple effect everywhere is not default on Android. More over ripple effect use shaders (as far as I know) so it will probably hurt performance if you place it on all Views.
So my recommendation is to make simple plugin that will allow you to change the background to rippleDrawable. Does this sounds good?
What do you think, how the plugin would be used then?
I mean, there already is a plugin by Brad martin to bring the ripple effect for Android and also for iOS here: here.
The reason why I did not want to use it is, that I would have to put the <RL:Ripple> ... </RL:Ripple>
around every single view where I want to have the ripple effect. That's why I think it would be better if all these Material Design effects came by default on Android (and maybe also on iOS) because this seems to be pretty basic in most of the mobile apps today.
I agree, that the Material Design ripple effects (and maybe other effects) are not really default on Android. But there are only very few steps necessary to apply them and it would be cool if this would be possible in NativeScript as well.
I got another example some weeks ago with customizing ActionItems here. The only thing I wanted to achieve was using a FontAwesome Icon instead of a static image source, so I wanted to keep the native touch effect of the ActionItem. But the view lost all of the native effects, just because I had to create a custom view there.
@felix-idf What I imagine is to have plugin that register a new Property
or CssProperty
(if you want it to set it through CSS) and when that property change you could add handler to loaded
event on the view. In that handler you will have the nativeView
of the view so it will be possible to call setBackground
with the resourceID of the rippleDrawable.
If this is CssProperty you should be able to set it to as many elements as you need through css. No need for changes in the XML. What do you think?
Actually I was hoping that this would be something related to the core in some day, as more and more Android and also iOS apps use Material Design (components, effects etc). I'm a little bit afraid of using too many plugins in our app, as there is never the guarantee that all of the plugins will stay up to date / compatible in the future.
Maybe my suggestion about setting the ripple effect everywhere (on all views) by default is too excessive. What about providing a property _showRippleOnTouch_ (or any other name) that is false by default and must be set to true in xml to show the ripple effect? This way you would still provide the native experience, as the ripple is not enabled by default for all views in the page like it isn't done in native Android development. But the developer can choose, which views or layout containers should show the ripple effect only by setting the property to true.
Do you think this could be an option? Or would that make no difference regarding performance issues?
I'm also interested in the opinion of the other guys here in this thread.
I honestly go back and forth on issues like this @felix-idf - while it is great if it's in the core, is it really something 'needed' right now 馃槃. Maybe a good option, for now, is a good plugin to expose this functionality (not the ripple plugin I did) and then if this gains more attention and desire the NS team can add it to the core.
Personally I would love to see it core, I mean it is a core native android feature that everyone keeps asking for\about. Could just point them at a doc and say "turn this on, she's off by default".
That's a very good point, I'm actually leaning with @sitefinitysteve now 馃槃 - have the option and a note about the performance implications when it's enabled on X views, yada yada.
...and he NEVER does, so this is special
+1
Making ripple like a boss...
float[] outer = {5, 5, 10, 10, 15, 15, 20, 20};
RectF inset = new RectF(4, 6, 8, 10);
float[] inner = {3, 3, 7, 7, 11, 11, 14, 14};
ShapeDrawable border = new ShapeDrawable();
border.setTint(0xFFFF0000);
border.setShape(new RoundRectShape(outer, inset, inner));
ShapeDrawable background = new ShapeDrawable();
background.setTint(0xFF00FF00);
background.setShape(new RoundRectShape(outer, null, null));
Drawable[] layers = { background, border };
LayerDrawable layerDrawable = new LayerDrawable(layers);
// If API >= 21
ColorStateList colorStateList = new ColorStateList(
new int[][] {
new int[]{android.R.attr.state_pressed},
new int[]{android.R.attr.state_focused},
new int[]{android.R.attr.state_activated},
new int[]{}
},
new int[] { 0xFF0000FF, 0xFF00FFFF, 0xFFFFFFFF, 0xFFFF0000 }
);
RippleDrawable ripple = new RippleDrawable(colorStateList, layerDrawable, background);
// endif
btn.setBackground(ripple);
This code is capable to draw custom background color, borders with custom corner radiuses and border thicknesses and optionally apply ripple given the 4 colors. We have to wrap the android specific ripple in a nice CSS property (e.g. --android-ripple: red green blue purple;
) and ship it.
woohoo
This would be good to have for a future {N} core theme revamp.
Just wanted to add that I created a simple plugin to add native ripples to any view on Android/iOS: https://www.npmjs.com/package/nativescript-ng-ripple
It uses a similar approach to @PanayotCankov on Android, which creates a native RippleDrawable. On iOS I tried to replicate the animation (it's a little bit off, but good enough). PRs are welcome.
Unfortunately it only works on angular because I created a directive, but should work if someone wants to move the code to a ContentView. At this time, it preserves the current background (which includes border-radius/color/etc).
I'm also planning to allow you to disable the ripple (so you can use it in a listview, for example, and it will not ripple on tap)
@edusperoni Thank you so much, going to use it.
@edusperoni your plugin based on https://github.com/bradmartin/nativescript-ripple but it's not native ripple effect.
Need really native ripple effect on Android for any view.
@webleaf I copied the exact code from nativescript-ripple. Only difference is I used a directive to hook the loaded event, while his plugin used a content view that hooked the loaded event and I've used a native RippleDrawable on Android, not a custom implementation. How is it not native?
@edusperoni sorry. May be I'm wrong. I just remember that when I tried nativescript-ripple, i did not like effect, which produce that plugin.
Could you tell more detailed, how implement your plugin to work with plain typescript (without Angular).
@webleaf the nativescript-ripple plugin uses a custom ripple implementation. You can check my repo, all the logic is in the directive ts file.
All I do on Android is listen to the loaded event and replace the background with a new RippleDrawable with the color of your choosing containing the original background and a mask that takes border radius in consideration. I also monkey patch the View's method to reapply the ripple if the background changes via CSS. You get the same exact effect you have on a button, for example.
On iOS I created my own ripple animation that mimics the RippleDrawable, but it can probably be improved.
The cardview plugin has recently added a ripple
property and I like the approach, I have not compared or inspected it in detail to determine the "best" approach for NS. If interested
[rippleProperty.setNative](value: boolean) {
if (!value) {
this.nativeView.setClickable(false);
} else {
const attr = java.lang.Class.forName('android.support.v7.appcompat.R$attr');
// https://developer.android.com/reference/java/lang/Class#getField(java.lang.String)
const field = attr.getField('selectableItemBackground') as java.lang.reflect.Field;
if (field && android.os.Build.VERSION.SDK_INT >= 23) {
const resId = field.getInt(null);
const attrs = Array.create('int', 1);
attrs[0] = resId;
const activity = application.android.foregroundActivity;
const typedValue = activity.obtainStyledAttributes(attrs);
const selectedItemDrawable = typedValue.getDrawable(0);
this.nativeView.setForeground(selectedItemDrawable);
this.nativeView.setClickable(true);
}
}
}
create transparent color
if you do not want to see ripple effect in tab then do this,
app:tabRippleColor="@color/transparent_fully"
Most helpful comment
Making ripple like a boss...
This code is capable to draw custom background color, borders with custom corner radiuses and border thicknesses and optionally apply ripple given the 4 colors. We have to wrap the android specific ripple in a nice CSS property (e.g.
--android-ripple: red green blue purple;
) and ship it.woohoo