I'm trying to change the height of the progress component in nativescript like this:
<Progress value="{{ progress }}" maxValue="{{totalTime}}" height="100">
</Progress>
But the height property has no effect. How do I change the height of this component?
You can change the height of ProgressBar using the height property (due to some spcific in the native controls).
However one of the gret advantages of NativeScript is that you have direct access to the native APIs for both iOS and Android. So after some small research here is how I managed to change the default scale (there might be even better approaches - this is one of the shortest I came upon).
TypeScript example:
Use the laoded event to get the reference to your progress bar in the code behind.
<Progress minValue="0" maxValue="100" value="25" loaded="onProgressLoaded"/>
Then in the code behind access the native controls
import { Progress } from 'ui/progress';
import { isAndroid, isIOS } from "platform"
declare let CGAffineTransformMakeScale: any; // or use tns-platform-declarations instead of casting to any
export function onProgressLoaded(args: EventData) {
let progress = <Progress>args.object;
if (isAndroid) {
progress.android.setScaleY(5); // progress.android === android.widget.ProgressBar
} else if (isIOS) {
let transform = CGAffineTransformMakeScale(1.0, 5.0);
progress.ios.transform = transform; // progress.ios === UIProgressView
}
}
Full demo app can be found here
You can directly set scaleY attribute of the progress element.
Example:
<Progress scaleY="2" value="{{ progress }}" maxValue="{{totalTime}}" height="100"></Progress>
This will make it 2 times wider in the vertical (Y) axis.
Related
I am implementing font size accessibility in a NativeScript-Vue app.
I want to allow or prevent Label resizing through an XML attribute for both Android and iOS, but behavior and implementation on the platforms are different.
Android
All labels are scaled by default. If I want a label not to resize, I need to call the function setTextSize in the loaded event, following this solution.
<Label text="Not resizable" #loaded="$androidFixedLabelSize($event, 70)" />
Vue.prototype.$androidFixedLabelSize = function({ object }, fontSize) {
if (object.android)
object.nativeView.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, utils.layout.toDevicePixels(fontSize));
}
iOS
Labels are not scaled by default. To resize a label, I need to use nativescript-accessibility-ext plugin and add the attribute accessibilityAdjustsFontSize.
<Label text="Resizable" accessibilityAdjustsFontSize="true" />
Having to add one attribute for fixed Android and one for resizable iOS is a bit cumbersome.
I was thinking of having all labels resizable by default, and specify if I want one not to resize through a directive or an attribute.
Can I achieve this through a custom directive? Or something else?
Update
I was able to prevent resizing on Android through a directive without hardcoding font size, but there is a problem: update is triggered only for few labels. el.nativeView.android in bind and inserted hooks is undefined.
Vue.directive("noresize", {
update: el => {
if (el.nativeView.android) {
el.nativeView.android.setTextSize(android.util.TypedValue.COMPLEX_UNIT_DIP, el.nativeView.fontSize);
} else {
// iOS code
}
}
});
On iOS, I would like to simply set accessibilityAdjustsFontSize="false", but this implies that it is true by default.
So the next question is: how do I set accessibilityAdjustsFontSize="true" on all Label components on iOS?
Thanks to Morten Sjøgren, developer of #nota/nativescript-accessibility-ext, I was able to add a global event. Accessibility resizing is now applied on all Label components, unless the attribute noResize is true.
app.js
import '#nota/nativescript-accessibility-ext';
import { Label } from 'tns-core-modules/ui/label';
// code
Label.on(Label.loadedEvent, ({ object }) => {
if (object.noResize) {
if (object.android) {
object.nativeView.setTextSize(android.util.TypedValue.COMPLEX_UNIT_DIP, object.fontSize);
}
} else {
object.accessibilityAdjustsFontSize = "true";
}
});
<Label text="Don't resize" noResize="true" />
I use a FlatList component for images grid because it have a good performance:
<FlatList
data={photos}
columnWrapperStyle={styles.listColumn}
numColumns={4}
renderItem={photo => this.renderPhoto(photo)}
/>
For now renderPhoto func return a new FastImage component (i use it because it have a cool caching feature)
<FastImage
resizeMode={FastImage.resizeMode.cover}
source={{uri: photo.src}}
/>
In the end I have something like this:
But now I want to have a very familiar possibility. Tap on the image will start the animation after which the image will be stretched to the full width of the screen.
After that, the user can do the following:
Swipe left/right to see prev/next images from the FlatList
Zoom current image
Tap on image to show/hide control elements (footer and header)
Swipe up/down for closing carousel and return to the grid component
It might look something like this:
So, whats a problem?
All existing carousel solutions are a wrapper for an image collection. But I cant pass wrapper component inside FlatList.
I could not find a ready-made component for solving such a common problem.
There are some that I try to combine (Lightbox, Carousel). But this solution will greatly affect performance. (I need to load the entire collection of images from the FlatList into the carousel component) In addition, such solutions usually have problems with animation.
So I'm wondering if there really is no react-native solution for such a popular image view mechanics?
Perhaps it is worth making a native module on the swift/objc (FlatList of images with carousel modal)?
Actually is possible with the elements that you have.
First you have the carousel (react-native-looped-carousel):
const activeProps = {
resizeMode: 'contain',
flex: 1,
width: null
};
const { height, width } = Dimensions.get('window');
const renderCarousel = (album, currentPage) => (
<Carousel style={{ width, height }} currentPage={currentPage} autoplay={false}>
{album.map(image => (
<FastImage
style={{ flex: 1 }}
resizeMode={FastImage.resizeMode.contain}
source={{ uri: image.uri }}
key={image.uri}
/>))
}
</Carousel>
);
Then FastImage (react-native-fast-image) with the lightbox (react-native-lightbox):
LightImage = (props) => {
const currentPage = this.items.findIndex(x => x.uri === props.source.uri);
return (
<Lightbox
activeProps={activeProps}
renderContent={() => renderCarousel(this.items, currentPage)}
>
<FastImage {...props} />
</Lightbox>
);
}
Now you can use your renderItem with the component for the FastImage and Lightbox
<FlatList
data={this.items}
columnWrapperStyle={styles.listColumn}
numColumns={4}
renderItem={photo => this.LightImage(photo)}
/>
I've copied part of my code, so it won't work with just copy and paste. If you have any question feel free to ask!
There's only one problem with this implementation that if you rotate the device the layout breaks
Can the size of the activity indicator be changed in Nativescript iOS?
Also the color.
It sure can, I did something like this in my main view:
if (frameModule.topmost().ios) {
var indicator = page.getViewById("indicator");
indicator.ios.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.UIActivityIndicatorViewStyleWhiteLarge;
indicator.ios.color = new colorModule.Color("#FFFFFF").ios;
}
I have this in my app.css which seems to do the trick for the color (I had no need to change the size yet):
ActivityIndicator {
color: #4CC55B;
}
I'm looking to animate a text field into view and a button out of view at the same time, so that it looks like the text field is replacing the button. (They are both equal size and take up the same area of the screen).
What's the best way to do this using React Native animation?
At this point, I am rendering the button if one of my state values is false, and the text field if it is true.
You can animate any style property in react-native using the Animated API.
If you are able to represent the changes in a sequence of style changes, the Animated API can do it. For instance animating the opacity from 1 to 0 and back to 1 will give a nice fade in fade out effect. The docs explain the Animations much more clearly
Also you can you selective rendering to mount or hide the component
<View style={{/*style props that need to be animated*/}}
{ boolShowText? <Text/> : <View/> }
</View>
The fading example as found in react-native docs
class FadeInView extends React.Component {
constructor(props) {
super(props);
this.state = {
fadeAnim: new Animated.Value(0), // init opacity 0
};
}
componentDidMount() {
Animated.timing( // Uses easing functions
this.state.fadeAnim, // The value to drive
{toValue: 1}, // Configuration
).start(); // Don't forget start!
}
render() {
return (
<Animated.View // Special animatable View
style={{opacity: this.state.fadeAnim}}> // Binds
{this.props.children}
</Animated.View>
);
}
}
developing for Gear s2 web app (Tizen),
how is it possible to scroll a page which has only text, using the bezel?
Thanks.
First you have to listen to the "rotarydetent" events, e.g. like following:
document.addEventListener('rotarydetent', onRotarydetent);
function onRotarydetent(ev) {
var direction = ev.detail.direction;
if(direction === "CW"){ // CW = clockwise; CCW = counterclockwise
... scroll down ...
} else {
... scrull up ...
}
}
So now to scroll the page content it depends on how build your web app. If you use the SDK Wizard and have a project including tau.js it will be simple if you know that tau adds a scroller container around each page. Now you just need to find the scroller and scroll it. Using jQuery it could look like following:
function onRotarydetent(ev) {
var direction = ev.detail.direction,
uiScroller = $('#pageid').find('.ui-scroller'),
scrollPos = $(uiScroller).scrollTop();
console.debug("onRotarydetent: " + direction);
if(direction === "CW"){
$(uiScroller).scrollTop(scrollPos + 100); // scroll down 100px
} else {
$(uiScroller).scrollTop(scrollPos - 100); // scroll up 100px
}
}
Have a look at the UIComponents sample app available within the Tizen Wearable SDK.
You need to use the TAU library to achieve Text scrolling using Beezel.
Create a new project using the UI Components app and Install it on Gear s2 emulator or original hardware. Then Run the app and click on the first option 'Header' which contains your use case i.e. plain text scrollable by beezel.