I'd like to defer as much loading as possible away from the splash screen and into a view page with a loading animation. How can I achieve that since I can't have the splash screen itself show a loading animation?
MauiSplashScreen should have supported Animation, however, this has hasn't been implemented and is a feature request: [Enhancement] MauiSplashScreen Video / Animation Support. The best we can do on Android 12 is trying to ignore or dismiss the SplashScreen through the OnCreate method below which would save the loading time.
public class MainActivity : MauiAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
}
}
For more details, you can refer to Customize the animation for dismissing the splash screen
Related
I want to change the style of title in stage but i couldn't find anything.
I tried some css codes like:
.title {
-fx-font-size: 18px;
-fx-font-family: "B Homa";
}
but it didn't work for me.I searched about the style of window in javafx and I figured it out that the default style of every native window is Decorated and for designing a custom window I must use UNDERCOATED mode, but I just want to change the size and font style of native window (different font and size) .
I think this is not possible with a decorated default window. The window itself is a native window from your OS. For example on windows the window implementation is:
com.sun.glass.ui.win.WinWindowand
the title is managed in a native method:
#Override native protected boolean _setTitle(long ptr, String title);
Is there a simple way to disable screen rotation in Qt for whole app? I just don't want to worry about that and simply disable it.
I am using Qt 5.8 and targeting Windows.
It's pointless, because screen rotation from your perspective is the same as a screen resolution change, and if you turn that off, your users will be rightly hating you.
If you wish to test your code for compatibility with screen rotation, emulate it by changing screen resolution.
The best way would be to disable rotation in Windows.
The only other way I see is to display your widgets/qml rotated according to the current device orientation.
Here is a code for obtaining current orientation under Windows (tested on Windows 8.1 tablet):
#include <Windows.h>
enum class EOrientation
{
Rotate_0,
Rotate_90,
Rotate_180,
Rotate_270
};
EOrientation CYourViewManager::getOrientation() const
{
DEVMODE deviceMode;
if (!EnumDisplaySettings(NULL, 0, &deviceMode))
return EOrientation::Rotate_0;
switch (deviceMode.dmDisplayOrientation)
{
case DMDO_90:
return EOrientation::Rotate_90;
case DMDO_180:
return EOrientation::Rotate_180;
case DMDO_270:
return EOrientation::Rotate_270;
}
return EOrientation::Rotate_0;
}
(I posted this initially on the Xamarin Forums, but then decided I might get a faster answer here?)
TL;DR: Some layouts will count a tap on a transparent background, others won't. Setting InputTransparent on a container sets it for all of its children, and I feel like children should be able to override the parent. I need to create elements that overlay another element and pass taps through a transparent region but still have tappable buttons. When I try this with a Grid, it doesn't work. I don't want to go back to AbsoluteLayouts. I'm mostly working in iOS right now, I'm not quite sure if it's a problem in Android yet. Windows Phone/UWP isn't on the table.
Longer version:
I'm rewriting some layouts that worked OK in an older Xamarin Forms (1.3 I think). We recently upgraded to 2.1, and it wreaked havoc on the layout code's bad decisions. I'm tasked with updating the layouts to behave themselves. While I recognize 2.2 has been released, I just tried an upgrade and everything I'm typing seems true in that version as well, so it's not a 2.1 vs. 2.2 issue, or at least if some improvements are made they aren't helping me.
It's a mapping application, so the centerpiece of all layouts is an expensive, temperamental OpenGL element. This element very much does not like to be reparented, so I've adopted a layout sort of like this imaginary XAML:
<ContentPage>
<CustomLayout>
<OurHeaderControl />
<TheMapControl />
<OurFooterControl />
<MapOverlay />
</CustomLayout>
</ContentPage
The purpose of "MapOverlay" is to implement our workflows by adding Xamarin elements on top of the header/footer areas and/or the map. For example, one layout adds a list of directions to the bottom above the footer, so it has less room for the map to appear. The custom layout understands this and lays out the map after the overlay so it can ask for the correct map bounds.
In this layout, I cannot tap on anything the MapOverlay is over. I can make it InputTransparent and tap those things, but then all of its children are also not tappable. This was not true in the old layouts.
Here's the only differences I see between the old layouts and the new:
The old layouts were a complicated mess of AbsoluteLayouts. It looked something like this, I didn't write it:
<ContentPage>
<AbsoluteLayout> // "main layout"
<AbsoluteLayout> // "map layout"
<Map /> // An AbsoluteLayout containing the OpenGL view.
</AbsoluteLayout>
<AbsoluteLayout> // "child layout"
<SubPage /> // An AbsoluteLayout
</AbsoluteLayout>
</AbsoluteLayout>
</ContentPage>
The main layout contains AbsoluteLayouts to constrain the child views. One child view is itself an AbsoluteLayout that contains the Map and a handful of other elements associated with it. The other child is the overlay, which is always an AbsoluteLayout that contains the elements relevant to that overlay. These layouts all reference each other in cycles and update each other as layout events change. It's a fascinating ping-ponging that eventually settles down. Usually. Sometimes things just disapper. Obviously there's a reason I'm rewriting it.
But I can click on what I need to click on at every layer, and I don't get that.
So, let's talk about what I need to work, and maybe figure out if it's a bug why it's not working, or if it's a coincidence that it worked with other layouts. Here's a non-XAML page layout that demonstrates, my project's got its roots in the days when you couldn't use XAML in shared libraries:
I need to be able to tap both buttons in this UI and have them respond.
public class MyPage : ContentPage {
public MyPage() {
var mainLayout = new AbsoluteLayout();
// Two buttons will be overlaid.
var overlaidButton = new Button() {
Text = "Overlaid",
Command = new Command((o) => DisplayAlert("Upper!", "Overlaid button.", "Ah."))
};
mainLayout.Children.Add(overlaidButton, new Rectangle(0.25, 0.25, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize), AbsoluteLayoutFlags.PositionProportional);
// The top overlay layout will be a grid.
var overlay = new Grid() {
RowDefinitions = { new RowDefinition() { Height = new GridLength(1.0, GridUnitType.Star) } },
ColumnDefinitions = {
new ColumnDefinition() { Width = new GridLength(1.0, GridUnitType.Star) },
new ColumnDefinition() { Width = new GridLength(1.0, GridUnitType.Star) },
},
BackgroundColor = Color.Transparent
};
var overlayingButton = new Button() {
Text = "Overlaying",
Command = new Command((o) => DisplayAlert("Upper!", "Overlaying button.", "Ah."))
};
overlay.Children.Add(overlayingButton, 0, 1);
mainLayout.Children.Add(overlay, new Rectangle(0, 0, 1.0, 1.0), AbsoluteLayoutFlags.All);
// This pair of property sets makes the overlaid button clickable, but not the overlaying!
// overlay.InputTransparent = true;
// upperOverlayButton.InputTransparent = false;
Content = mainLayout;
}
}
This only lets me tap the "overlaying" button even when I change the Grid to an AbsoluteLayout.
I'm stumped. It took me 2 weeks to debug the initial layouts and come up with a new solution. I really don't want to disassemble all of our layouts and put everything in one big AbsoluteLayout or a custom layout. In WPF, there were two kinds of transparent: "transparent background" meant the background could still hit test, and "null background" meant the background would not hit test. Is there some way to overlay layouts in Xamarin like this?
Or, more appropriate, why is the convoluted nest of numerous AbsoluteLayouts in our old layouts working like I need it to, but this much simpler layout isn't?
updates
Here's some additional information I remembered:
This behavior is iOS specific. On Android, both the example code and our code work.
I'm not the first person to have this problem: On StackOverflow. On Xamarin's Forums.
In general it seems as if the behavior with iOS in regards to how InputTransparent is being handled in a Grid compared to the other two platforms. I'm not particularly certain whether I'd quantify the current behavior as a bug at this time, but I understand that it's frustrating to run into a disparity in platform behavior.
There is a fix of sorts for your situation, though, if I'm understanding it correctly. It appears similar a similar report was filed before and behavior regarding iOS was mentioned via this SO link. The question is posed in the scope of a non-Forms iOS app, but the logic can be applied here.
By using a custom renderer (let's use a CustomGrid as an example), you can specifically implement the iOS implementation of the Grid to follow the aforementioned link's manner of finding underlying views:
CustomGrid.cs (PCL):
public class CustomGrid : Grid
{
public CustomGrid() { }
}
CustomGrid.cs (iOS):
[assembly: ExportRenderer(typeof(CustomGrid), typeof(CustomGridRenderer))]
public class CustomGridRenderer : ViewRenderer
{
public override UIKit.UIView HitTest(CoreGraphics.CGPoint point, UIKit.UIEvent uievent)
{
UIView hitView = base.HitTest(point, uievent);
if (hitView == this)
{
return null;
}
return hitView;
}
}
In this manner you should not explicitly set InputTransparent for iOS, and any taps on the Grid itself are sent through to anything below. Since Android works with InputTransparent, though, in this particular case you can wrap that inside a Device.OnPlatform statement and skip implementing the Android custom renderer if you don't want to:
Device.OnPlatform(Android: () =>
{
overlay.InputTransparent = true
});
Using your above code modified to use the CustomGrid and iOS renderer, I'm able to tap both buttons.
I'm trying to stop a QML video and show its last frame when playback has finished. Does anybody know how to do this? (Sorry, this seems to be not as trivial as it sounds...)
At the moment, my problem is that the Video element simply becomes invisible/hidden after playback is done. (onVisibleChanged is never called.)
When I use the hack in onStatusChanged in my code, the video disappears for a moment after the end and then shows the end of the video.
What I'm doing is simply:
Video {
anchors.fill: parent
fillMode: VideoOutput.PreserveAspectFit;
source: "path/to/file"
autoPlay: true
onStatusChanged: {
console.warn("StatusChanged:"+status+"|"+MediaPlayer.Loaded)
if (status == MediaPlayer.EndOfMedia)
{
// seek a bit before the end of the video since the last frames
// are the same here, anyway
seek(metaData.duration-200)
play()
pause()
}
}
onVisibleChanged:
{
console.log(visible)
}
}
It's possible that I'm missing something, but I could not find anything on this topic in the docs. Also, using separate MediaPlayer and VideoOutput does not change the behavior.
For the record, I'm using the latest Qt 5.2 on Windows (msvc2010+OpenGL-build).
I'm still looking for a better solution to this. What I've come up with is to pause the video one second before it's over:
MediaPlayer {
autoLoad: true
id: video
onPositionChanged: {
if (video.position > 1000 && video.duration - video.position < 1000) {
video.pause();
}
}
}
Why one second? On my machine if you try to pause it about 500ms before the end, the video manages to run to completion and disappear from view without even registering the pause() call. Thus 1 second is sort of a good safe value for me.
Frankly, I'd prefer if there was a more explicit way to tell the MediaPlayer what to do at the end of the video. I know for a fact that GStreamer, which is what Qt uses on Linux and Mac, notifies you when the video is almost over so that you can decide what to do next - e.g. pause the video or loop it seamlessly.
I share your pain (mainly interested in OSX and iOS, where the same problem occurs). The only solution I have is to pair each video (which at least are "canned" app resources, not dynamic content off the net) with a png image of their final frame. When the video starts, enable display of the image under it (although it's not actually visible at that point). When the video ends abruptly, the image is left visible.
This works perfectly on iOS, but on (some?) Macs there may a slight brightness jump between the video and the image (guessing: something to do with OSX display preferences' screen calibration not affecting video?)
An option to the MediaPlayer or VideoOutput element types to freeze on the last frame would indeed be much simpler.
One other possibility I've considered but not tried would be stacking two videos. The one on top is the main player, but the one underneath would just be seeked to, say, the last millisecond of the video and paused. Then when the main video finishes and disappears... there's as-good-as the final frame of the video showing there underneath. This'd basically be the same as the image-based solution, but with the image underneath being dynamically created using a video player. I've found mobile HW's video and Qt's wrappings of it to be temperamental enough (admittedly more back in the earlier days of Qt5) to really not want to try and do anything too clever with it at all though.
A few years later and I am facing the same issue. However, I found a workaround (for Qt >= 5.9) that allows me to pause the video within 100 ms of the end:
It seems that the issue is related to the notifyInterval property (introduced in Qt 5.9). It is by default set to 1000ms (same as the 1000ms observed in other answers, not a coincidence I believe). Thus, changing it to a very small value when the video is almost done allows for catching a position very close to the end and pausing the video there:
Video {
id: videoelem
source: "file:///my/video.mp4"
notifyInterval: videoelem.duration>2000 ? 1000 : 50
onPositionChanged: {
if(position > videoelem.duration-2*notifyInterval) {
if(notifyInterval == 1000)
notifyInterval = 50
else if(notifyInterval == 50)
videoelem.pause()
}
}
onStatusChanged: {
if(status == MediaPlayer.Loaded)
videoelem.play()
}
}
Hope this helps somebody!
in MediaPlayer element: Pause the video 100ms before end based on duration
MediaPlayer {
id: video1
onPlaybackStateChanged: {
if(playbackState==1){
durTrig.stop();
durTrig.interval=duration-100;
durTrig.restart();
}
}
}
Timer:{
id:durTrig
running:false
repeat: false
onTriggered:{
video1.pause();
}
}
I'm digging into customizing controls via CSS and I got pretty far. So I'm able to fully customize my scrollbar by e.g. setting track's background to transparent and so on. But I'm stuck with the ScrollBarSkin (investigated via ScenicViewer). It seems that this skin has a default background color (gradient) and a border, which I'm not able to modify.
So my question is, how can i access the e.g. TableCellSkin or ScrollBarSkin, to modify background color and insets via CSS?
edit: I'm using jdk7
edit2: i found some syntax in the caspian.css for the ScrollPaneSkin. I tried the same for the scrollbar and a tablecell with:
ScrollBarSkin>* {
-fx-base: transparent;
-fx-border-color: #00ff00;
-fx-background-color: #0000ff;
}
but with no luck.
found solution based on jewelsea's answer (thx mate!)
I made a new class extending ScrollBarSkin and I'm overriding the getSkinnable(). This looks like this:
public class MyScrollBarSkin extends ScrollBarSkin{
public MyScrollBarSkin(ScrollBar scrollBar) {
super(scrollBar);
}
#Override
public Insets getInsets() {
// TODO Auto-generated method stub
return super.getInsets();
}
#Override
public ScrollBar getSkinnable() {
ScrollBar curr = super.getSkinnable();
curr.getSkin().getNode().setStyle("-fx-background-color: transparent;");
return curr;
}
}
In the corresponding css I refer to this skin as jewelsea mentioned. Et voila!
One little question is still left: why I'm not able to directly access this component via css?
ScrollBarSkin is a class representing the skin used to render the ScrollBar. Here is an extract from a default JavaFX style sheet:
.scroll-bar {
-fx-skin: "com.sun.javafx.scene.control.skin.ScrollBarSkin";
}
Here is a link to ScrollBarSkin.java in the JavaFX 8 source repository. Note that it is a com.sun class, so it is not part of the public API and could disappear or change API between minor JavaFX releases without notice.
You can override the default skin with your own skin via the following css in your user stylesheet:
.scroll-bar {
-fx-skin: "com.mycompany.control.skin.CustomScrollBarSkin";
}
I just made the name and path up, you can use whatever you want.
What the skin is allowing is programmatic control over the look of the a control (i.e. it's only incidentally related to css because css is one way to set the skin on a control).
Customizing Skins is documented (to a certain extent) in the OpenJFX wiki.
The skin customization relies on a new JavaFX 8 class called SkinBase, which forms part of the javafx.scene.control public API.
Customizing skins in versions lower than Java 8 is not recommended, because then you will be working with old, undocumented and unsupported private APIs which will not work with Java 8 and later. Customizing skins in Java 8 is fine because it relies on the public API.
I'm pretty sure from your question that this isn't really what you are looking for, but it is the answer to your question (at least as I understood it).