JoshDSommer / nativescript-ngx-shadow

Angular directive to apply shadows to native elements according to the elevation level guidelines of material design specification
Apache License 2.0
9 stars 6 forks source link

iOS/Android Shadow inconsistency #4

Closed edusperoni closed 6 years ago

edusperoni commented 6 years ago

Continuing from https://github.com/Especializa/nativescript-ng-shadow/issues/9

I was testing my app on Android only and it was all fine and beautiful, but when I moved to iOS, the shadows were not appearing. Turns out actually setting a background color/border/border-radius or ANYTHING on an iOS view enables "clipsToBounds", which ends up clipping the shadow.

In the end, even with my latest PR which solves CSS issues on Android, we still have other issues on iOS. The solution is actually simple: just enable shadow on an empty view and draw whatever you need inside it (see https://stackoverflow.com/questions/41475501/creating-a-shadow-for-a-uiimageview-that-has-rounded-corners/41475658)

I'm opening this issue for discussion on how to solve this once and for all. I believe the goal for any Nativescript plugin or app is to have Android and iOS share most of the same code when possible.

I've been brainstorming a solution and I'll try to start working on one monday. The way I see it, we can go the {N} route and create something like https://github.com/bradmartin/nativescript-ripple:

view.android.ts // ContentView which does nothing but pass everthing to whatever it is wrapping. View.android would return Child.android
view.ios.ts // Creates a new UIView and add childs to it. 

Or something purely angular:

<Shadow params>
<!-- content -->
</Shadow>

Shadow component creates a Layout (maybe GridLayout?) styled on Android, and or iOS, creates this same Layout but wrapped with another (unstyled) layout.

The ideal scenario would be hooking the first child on Android and just creating a wrapper on iOS (so we would not be creating useless views), but I don't how feasable this is.

Here's an example of the component template:

<android>
    <GridLayout shadow(...) class=(...)>
        <ng-content>
    </GridLayout>
</android>
<ios>
    <GridLayout shadow(...)>
        <GridLayout class=(...)>
            <ng-content>
        </GridLayout>
    </GridLayout>
</ios>

This component would only add to current functionality, allowing people to use purely the directive or the "automagically" way;

Thoughts?

JoshDSommer commented 6 years ago

@edusperoni that sounds completely feasible to me. I'm actually using the same layout technique here https://github.com/TheOriginalJosh/Subular/blob/master/apps/mobile/app/views/player/player.component.html#L14 to create a shadow with rounded corners.

I think to accomplish this we may want to look into injecting the NativeScriptRender (import { NativeScriptRenderer } from 'nativescript-angular') into the directive and then use it to add the wrapping layout element. I've done similar manipulations of the UI with directives on the web using Angular's Render2 service and I think the same idea should work here.

JoshDSommer commented 6 years ago

@edusperoni I've added the above logic in a PR. check it out and let me know what you think. I would like to find a way to only add the wrapping container should it need to be in the case with border radiuses instead of every single time the shadow directive is applied. I may be overthinking this though.

https://github.com/TheOriginalJosh/nativescript-ngx-shadow/pull/5

edusperoni commented 6 years ago

@TheOriginalJosh Wow, that's way cleaner than what I imagined. Tomorrow morning I'll try it out and test CSS changes and such to make sure everything is good.

Nice work!

edusperoni commented 6 years ago

I absolutely forgot to comment on this after testing it out. CSS changes worked fine and the app behaves the same as its android counterpart. I'm already using it in my own app.

Amazing work!

JoshDSommer commented 6 years ago

@edusperoni awesome glad it works for you.