Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop Shadow support for View, Text, Image, and more #2800

Open
RobMeyer opened this issue Jul 18, 2019 · 5 comments
Open

Drop Shadow support for View, Text, Image, and more #2800

RobMeyer opened this issue Jul 18, 2019 · 5 comments
Labels
API: Completion Area: Paper enhancement Old Architecture Broad category for issues that apply to the RN "old" architecture of Cxx Modules + Paper Partner: Office Partner: Stream (label may be applied by bot based on author) Partner: Xbox (label may be applied by bot based on author) Workstream: Component Parity Close the parity gap between RNW and RN for core RN components and their supporting APIs.
Milestone

Comments

@RobMeyer
Copy link
Contributor

RobMeyer commented Jul 18, 2019

Proposal: Drop Shadow support for View, Text, Image, and more

Implement support for ViewStyle.shadow* and TextStyle.textShadow* for View, Text, and Image.

Summary

Tasks

  1. A C++/winrt port of DropShadowPanel, to be called ShadowedContentControl will be used for shadows cast from all XAML-based components.
  2. Implement TextStyle.textShadow* support
  3. Implement ViewStyle.shadow* support for ViewStyle.border* and ViewStyle.backgroundColor props
  4. Implement ViewStyle.shadow* support for RN , ImageViewManager
  5. Optionally, extend and share ShadowedContentControl for reuse by third parties

Motivation

React Native supports shadows for View, Text, and Image using the ViewStyle.shadow* and TextStyle.textShadow* props. Android and iOS both support these properties (though with some notable differences), but support hasn’t been implemented in react-native-windows vNext yet. The WPF RN project has support but a straight port to UWP isn’t possible due to differences in shadow APIs available between WPF and UWP + XAML + Composition.

Shadows will improve application visuals and usability. In addition to aiding visualization of the application's information hierarchy and drawing attention to UX of interest, drop shadows can also be used to enhance readability of text against low-contrast or "busy" background content such as a photograph. A shadow without vertical or horizontal offsets can also be used to create a "glow" effect, used for similar design and usability goals.

Basic example

<View>
        <Text style={{shadowColor: "red", shadowRadius: 2, shadowOpacity: 1, shadowOffset: {width: 1, height: 1}}}>This is text using ViewStyle.shadow* props</Text>
        <Text style={{textShadowColor: 'red', textShadowRadius: 2, textShadowOffset: {width: 1, height: 1}}}>This is text using TextStyle.textShadow* props</Text>

        <Image source={{uri: 'https://cdn.freebiesupply.com/logos/large/2x/disney-1-logo-png-transparent.png'}} style={{width: 200, height: 200, shadowColor: "red", shadowRadius: 2, shadowOpacity: 1, shadowOffset: {width: 1, height: 1}}} />

        <View style={{width: 300, height: 50, backgroundColor: "blue", shadowColor: "red", shadowRadius: 2, shadowOpacity: 1, shadowOffset: {width: 1, height: 1}, marginBottom: 20}} />

        <View style={{width: 300, height: 250, borderColor: "blue", borderWidth: 5, borderRadius: 20, borderStyle: 'dotted', shadowColor: "red", shadowRadius: 2, shadowOpacity: 1, shadowOffset: {width: 1, height: 1}}}>
          <Text>Shadow on a view with dotted border. Child elements (text and image) inherit ViewStyle.shadow* props</Text>
          <Image source={{uri: 'https://cdn.freebiesupply.com/logos/large/2x/disney-1-logo-png-transparent.png'}} style={{width: 200, height: 200}} />
        </View>
</View>

RN DropShadow Android and iOS

Open Questions

View shadows, iOS, Android, and staging work

iOS and Android's support for shadows on elements differs in one important way: on iOS all the children of the view also get the same drop shadow visuals applied to them. On android, the view's shadow only affects the view's border and background visuals, not all the children too. This can be seen in the screenshot above.

Android's model seems ideal because it allows for the most flexibility. On iOS, if you want a View's border to have shadow visuals, but you don't want the children to, then you have to put the children in another superimposed view. On Android, you simply set the shadow props on all the elements you want to have shadows. Similarly, in the event where child and a parent should both have shadows, on Android you're able to use the specialized textShadow props on the Text, which visually look better than iOS's inherited ViewStyle.shadow* visuals (see first two Text shadows in screenshot above).

However, I can guess how iOS' behavior came about. If we were to implement ShadowedContentControl using the "SoftwareBitmap -> CompositionBrush -> AlphaMask" technique, the shadow visuals would apply not only to the View itself, but also all children.

With that background information out of the way, we can discuss work staging. Rewriting ViewViewManager to use Composition border rendering instead of a XAML control would be a substantial task. The fastest path to supporting View shadows is to use the "SoftwareBitmap -> CompositionBrush -> AlphaMask" technique. However, this would mean children inherit shadows, like iOS. It also would be inferior performance-wise. Luckily, shadows are opt-in so it's pay-for-play.

Long-term there seems to be agreement on adopting Composition for a plethora of benefits (smaller XAML tree, improved performance, support for ViewStyle.borderStyle "dotted" and "dashed", etc.), but ShadowedContentControl + SoftwareBitmap -> CompositionBrush -> AlphaMask could help us get to basic drop shadow support faster. The short-term work also wouldn't go wasted, because it accrues towards making ShadowedContentControl work with arbitrary XAML types, useful for third parties wanting shadows for their own custom NativeComponents written wrapping XAML components.

RN Glyph / NativeComponent "PLYIcon"

IconViewManager is currently implemented using Glyph, not a XAML . We would like shadow support for these elements too, but I'm not sure which implementation would be preferred. Some possibilities:
a. If ShadowedContentContainer has support for arbitrary XAML content via the SoftwareBitmap -> CompositionBrush -> AlphaMask approach, Glyph could be wrapped in a ShadowedContentContainer.
b. IconViewManager could be rewritten to use instead of Glyph. The TextBlock could then be wrapped using ShadowedContentContainer.
c. IconViewMangager could be rewritten to be drawn using Composition with DropShadow.
d. Alternatively, our client could migrate from Glyph-based icons to using or components.

Popup/Flyout and Context Menu

Shadows are also of interest for these components but I haven't investigated enough to include anything along with this proposal.

Further reading, dev plan notes

2020/10/28: Attaching investigation notes I put together back in July 2019 when I was formulating a plan of attack. These notes were only intended for personal purposes and haven't been cleaned up for broad publication, so grant me a little leeway regarding rough edges. I hope it helps anyone that might pick up this task in the future.
Drop Shadows in react-native-windows.pdf

@ghost ghost added the Needs: Triage 🔍 New issue that needs to be reviewed by the issue management team (label applied by bot) label Jul 18, 2019
@harinikmsft
Copy link
Contributor

Thanks for writing this up @RobMeyer !

One thing occurs off the top of my head - DropShadowPanel is a Windows Community toolkit control. Is the best approach here to wrap a high policy control or should we go directly to Windows.UI.Composition.DropShadow and implement a layer around that in RNW instead?

Let's discuss in an upcoming review.

@RobMeyer
Copy link
Contributor Author

I think DropShadowPanel's approach is the only way that works because of some unfortunate restrictions of ElementCompositionPreview and DropShadow.

Only SpriteVisual and LayerVisual have a .Shadow property used to attach a shadow to an existing visual. Visual, which is what is exposed by ElementCompositionPreview, doesn't have a Shadow property.

It's still possible to create a new SpriteVisual and attach a DropShadow initialized using Mask (acquired from TextBlock.GetAlphaMask, Image.GetAlphaMask, or Shape.GetAlphaMask), but the SpriteVisual needs to be inserted in the XAML tree somewhere. Two ways to do this:

  1. Insert into a XAML element's Composition tree using ElementCompositionPreview::SetChildElementVisual. Unfortunately, this API doesn't give you control over the Z-Order. The Shadow always appears above the XAML content that is the source of the shadow.
  2. Create a sibling element (that is lower in Z-order) and set the Composition SpriteVisual, again using SetChildElementVisual. The second approach is eactly what DropShadowPanel does.

@harinikmsft harinikmsft removed the Needs: Triage 🔍 New issue that needs to be reviewed by the issue management team (label applied by bot) label Jul 24, 2019
@chrisglein chrisglein changed the title [PROPOSAL]: Drop Shadow support for View, Text, Image, and more Drop Shadow support for View, Text, Image, and more Aug 10, 2019
@chrisglein chrisglein added this to the vNext Milestone 5 milestone Aug 23, 2019
@harinikmsft harinikmsft added Partner: Office Partner: Stream (label may be applied by bot based on author) Partner: Xbox (label may be applied by bot based on author) must-have p1 labels Oct 25, 2019
@chrisglein chrisglein removed the vnext label Mar 18, 2020
@giregk
Copy link

giregk commented May 6, 2020

For your information, in iOS, children will not get the shadow property if a background color is set on the view ;)

@chrisglein chrisglein added this to the 0.66 milestone Apr 24, 2021
@chrisglein chrisglein modified the milestones: 0.66, 0.67 Aug 31, 2021
@chrisglein chrisglein modified the milestones: 0.67, 0.68 Oct 26, 2021
@chrisglein chrisglein modified the milestones: 0.68, Backlog Jan 17, 2022
@juhasuni
Copy link

juhasuni commented Feb 6, 2023

Any chance of moving forward with this? I believe that the fact that shadow properties are still missing might come as a surprise for anyone coming to RNW development 🥸

@vinaykumardetrix
Copy link

can any one helps in creating shadow properties that has to be work on react native windows application using react native components or using svg components

for now i was using imagebackground that has image shadow and on top of that i was showing view data to overcome this any help from react native community

@microsoft-github-policy-service microsoft-github-policy-service bot added the Old Architecture Broad category for issues that apply to the RN "old" architecture of Cxx Modules + Paper label May 22, 2024
@chiaramooney chiaramooney added the Workstream: Component Parity Close the parity gap between RNW and RN for core RN components and their supporting APIs. label Oct 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API: Completion Area: Paper enhancement Old Architecture Broad category for issues that apply to the RN "old" architecture of Cxx Modules + Paper Partner: Office Partner: Stream (label may be applied by bot based on author) Partner: Xbox (label may be applied by bot based on author) Workstream: Component Parity Close the parity gap between RNW and RN for core RN components and their supporting APIs.
Projects
None yet
Development

No branches or pull requests

8 participants