Prevent keyboard from resizing view on iOS/Android in Ionic 4 - ionic-framework

I have a background image that I want to have full screen with an input section at the bottom. When the input is focused, the keyboard appears and shrinks the image to fit the screen. What I want is for the image to push the full div up without re-sizing it.
I've tried numerous things, but my current attempt is as follows:
.background{
url('assets/background.png') center center fixed;
height: 100%;
width: 100%;
}
.input-area{
position: absolute;
left: 10px;
bottom: 10px;
right: 10px;
}
<div class="background">
<div class="input-area">
//textboxes
</div>
</div>
This seems like it should be easy to accomplish, but can't get the desired outcome. Any input would be appreciated, thanks.
ionic cli 4.12.0
#ionic/angular 4.4.0
#ionic-native 5.5.1
node v10.15.2
npm 6.4.1
cordova 8.1.2 (cordova-lib#8.1.1)

this is how I managed to do it:
I added an id to my ion-content and ion-toolbar in html file to reference them in my typescript file
...
<ion-content #content >
...
<ion-toolbar #toolbar color="light">
<ion-input #input >...
...
in my typescript I referenced them with ViewChild and added the functionality in the constructor like this
...
#ViewChild('content', {read: ElementRef}) contentRef: ElementRef;
#ViewChild('toolbar', {read: ElementRef}) toolbarRef: ElementRef;
...
private startkeyboardAnimationTimestamp = 0;
private endkeyboardAnimationTimestamp = 0.3;
private keyboardAnimationDuration = 0.3;
...
constructor(private renderer: Renderer2) {
if (this.platform.is('capacitor')) {
window.addEventListener('keyboardWillShow', (e) => {
this.startkeyboardAnimationTimestamp = Date.now();
this.keyboardHeight = (<any>e).keyboardHeight;
this.renderer.setStyle(this.contentRef.nativeElement, 'transform', `translate3d(0, ${-this.keyboardHeight}px, 0)`);
this.renderer.setStyle(this.contentRef.nativeElement, 'transition', `${this.keyboardAnimationDuration}s ease-in-out`);
this.renderer.setStyle(this.toolbarRef.nativeElement, 'transform', `translate3d(0, ${-this.keyboardHeight}px, 0)`);
this.renderer.setStyle(this.toolbarRef.nativeElement, 'transition', `${this.keyboardAnimationDuration}s ease-in-out`);
window.addEventListener('keyboardDidShow', (e) => {
this.endkeyboardAnimationTimestamp = Date.now();
});
window.addEventListener('keyboardWillHide', () => {
this.renderer.setStyle(this.contentRef.nativeElement, 'transform',
`translate3d(0, 0px, 0)`);
this.renderer.setStyle(this.toolbarRef.nativeElement, 'transform',
`translate3d(0, 0px, 0)`);
});
...
** as for the keyboardAnimationDuration I have it default to 0.3s and update it after the first show and hide.

This worked for me:
in the AndroidManifest.xml
android:windowSoftInputMode="adjustResize"
In the scss:
ion-content{
--background: url("./../../../assets/img/login-bg.jpg") no-repeat fixed center;
padding: 0;
}

Related

Flutter web app progress indicator before loading app?

Hi I am a mobile app developer and not much familiar with web development, I was finding any approach to implement Progress Indicator before loading the flutter web app like Gmail loading screen. Flutter web is cool but it takes few moments before loading the app. Can we add any indicator for this loading duration? Any code implemented in flutter would be the part of flutter app and it won't work, There should be another approach to achieve this.
With the help of #Abhilash, I was able to accomplish this. I got loader code from w3schools.
My project/web/index.html is like this.
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script defer src="index.dart.js" type="application/javascript"></script>
<style>
.loading {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid blue;
border-right: 16px solid green;
border-bottom: 16px solid red;
border-left: 16px solid pink;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div class="loading">
<div class="loader"></div>
</div>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
In your question you mentioned
Any code implemented in flutter would be the part of flutter app and it won't work,...
I assume you tried to add the splash screen approach for android or IOS. Since flutter-web is simply an index.html and a couple of js files(for eg., main.dart.js), you should perhaps try the CSS loading animation trick. Since you didn't share any code I am not writing any code but the following would be my approach as explained by this red stapler video. He/she kindly provided a lot of CSS based animations here along with the codepen implementations for that.
So following would be my steps in the flutter_web_project\web\index.html file.
Add a span element in the body of index.html to show the css animation itself.
Create a div wrapper to position the span animation in your index.html.
Then listen to the onLoad event of the window and remove the div element from your page or fade it out as described in the video.
In addition to answer of #Shahzad Akram you should remove the loading div because in Safari browser it may cause of flickering. So in the first screen you need to implement the folowing code (for example, in initState method):
import 'package:universal_html/html.dart'
...
#override
void initState() {
super.initState()
// Remove `loading` div
final loader = document.getElementsByClassName('loading');
if(loader.isNotEmpty) {
loader.first.remove();
}
}
P.S. For nice loaders you can visit loading.io.
Adam's answer will remove loader before flutter is actually loaded.
I found this script to be the most complete answer:
<html>
<head>
<style>
.loading {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.loader {
border: 8px solid #f3f3f3;
border-radius: 50%;
border-top: 8px solid #00AD87;
border-right: 8px solid #C30E48;
border-bottom: 8px solid #00AD87;
border-left: 8px solid #C30E48;
width: 60px !important;
height: 60px !important;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<!-- First time loading -->
<div class="loading">
<div class="loader"></div>
</div>
<!-- Ensure first time loading progress is gone after app loads -->
<script>
window.addEventListener("flutter-first-frame", function() {
var element = document.getElementsByClassName("loading");
element[0].parentNode.removeChild(element[0]);
});
</script>
<script defer src="main.dart.js" type="application/javascript"</script>
</body>
</html>
If you want to remove loading div with just JS use this code
<script>
window.onload = (event) => {
console.log('page is fully loaded');
var element = document.getElementById("loader");
element.parentNode.removeChild(element);
};
</script>
Notice that it assumes that loader is a <div id="loader"></div> tag
In addition to answers from #Shahzad and #BambinoUA, I also needed to add defer keyword for main.dart.js script tag as well.
<script defer src="main.dart.js" type="application/javascript"></script>
Below is my scenario where this was needed:
app was hosted on Gitlab pages
browser was Chrome (with a slow internet)
In this case, only blank screen was visible until the whole script is downloaded. Then the animation was visible only for 0.5 second and flutter widgets loaded immediately after that. Thus failing the purpose of having loading animation. This doesn't happen in local testing.
I also tried putting the animation div before all scripts, but it didn't help.
I think the accepted answer is partially right as it's presented a loading indicator rather than a progress indicator. From flutter doc you can have a rough estimation of the flutter's actual loading progress. I've compiled an example using this indicator and it's showcased here.
Add this style
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
}
.progress-bar__container {
width: 80%;
height: 2rem;
border-radius: 2rem;
position: relative;
overflow: hidden;
transition: all 0.5s;
will-change: transform;
box-shadow: 0 0 5px #e76f51;
}
.progress-bar {
position: absolute;
height: 100%;
width: 100%;
content: "";
background-color: #e76f51;
top:0;
bottom: 0;
left: -100%;
border-radius: inherit;
display: flex;
justify-content: center;
align-items:center;
color: white;
font-family: sans-serif;
}
.progress-bar__text {
display: none;
}
and append this code on index.html of your flutter app.
function updateProgress(num) {
const progressBarContainer = document.querySelector('.progress-bar__container');
const progressBar = document.querySelector('.progress-bar');
const progressBarText = document.querySelector('.progress-bar__text');
let time = 0;
let endState = 100;
gsap.to(progressBar, {
x: num + "%",
duration: 2,
});
}
window.addEventListener('load', function(ev) {
var loading = document.querySelector('#loading');
loading.textContent = "Loading entrypoint...";
updateProgress(15);
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: async function(engineInitializer) {
loading.textContent = "Initializing engine...";
updateProgress(50);
let appRunner = await engineInitializer.initializeEngine();
updateProgress(80);
loading.textContent = "Running app...";
await appRunner.runApp();
updateProgress(100);
}
});
});
During startup of a flutter web app, we have the 2 phases: the first phase is when the index.html page has already loaded but the actually flutter app is loading. Then when the flutter app is loaded, we still might need to do some preparation within the flutter app. I like both phases to show an indication of loading and I want this to be the same. So... what I did:
First my index.html displays a gif which shows a circular progress indicator similar to the one I have in flutter (see 2) loading.gif
I do this similar to what this person describes: https://retroportalstudio.medium.com/indicate-website-loading-for-flutter-web-apps-7dc5e2c59e24
Then in my flutter app, I show this indicator:
return Container(
decoration: BoxDecoration(color: Colors.white),
child: Center(child: CircularProgressIndicator())
);
This indicator is pretty much the same as the gif. I created this gif with a combination of https://gifcap.dev/ and gimp to crop it.
The result is a fairly smooth loading circular progress indicator almost instant upon opening my website all the way up to when my flutterweb app opens.

Ionic 3 Button is not totally fixed at the footer and it moves while scrolling

I need to fix a button at the bottom of an ionic 3 project page.
The actual scss script works but the button is not totally fixed to the bottom, and it moves while scrolling.
Here is the sass script:
.fixedBtn{
width: 100%;
position: fixed;
left: 0;
bottom: 10px;
right: 0;
}
I tried to use flex:
div{
display: flex;
flex-direction: column;
}
But the result was as shown in this stackblitz, not the right behavior.
put this :
<button ion-button primary class="fixedBtn">a</button>
out side of ion-content
should be like
<ion-content>
/** your content */
</ion-content>
<button ion-button primary class="fixedBtn">a</button>
and in your sass file :
.fixedBtn{
width: 100%;
position: fixed !important;
left: 0;
bottom: 50px;
right: 0;
}

Ionic 3 - Keyboard pushes content up, and over other content, with no reason

I am working on a simple app in Ionic.
I have a problem that the keyboard pushes my input field up and over another div while there is enough space for they keyboard. How do I fix this? I already looked around on the internet but wasn't able to find any solution to my problem.
This is what happens:
As you can see, the text is in the image and there is no reason for it being so high. There is more then enough space below it.
This is my code:
HTML:
<ion-header>
<ion-navbar>
<ion-title>Login</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding class="login content">
<div class="logo-container">
<img src="assets/imgs/Mikos_logo.jpeg" class="logo-img">
</div>
<div class="center">
<p>Vul hier je naam in:</p>
<ion-item class="code-field">
<ion-input placeholder="naam" type="text" (keyup)="nameInput()" [(ngModel)]="name"></ion-input>
</ion-item>
</div>
</ion-content>
CSS:
page-login {
.login {
background-color: #EEEEEE;
}
.logo-container{
position: absolute;
width: 400px;
left: calc(50% - 400px / 2);
}
.logo-img{
display: block;
width: 100%;
height: auto;
}
.center{
position: absolute;
top: 40%;
width: 300px;
left: calc(50% - 300px / 2);
}
#media only screen and (max-width: 600px) {
/* For mobile phones: */
.logo-container{
position: absolute;
width: 300px;
left: calc(50% - 300px / 2);
}
}
}
What I have tried:
I have added the Ionic native keyboard and added this in my app module:
IonicModule.forRoot(MyApp, { scrollAssist: false, autoFocusAssist: false } ),
This unfortunately did not work.
Update:
Adding
.scroll-content {
padding-bottom: 0 !important;
}
is also not working.
This is a known bug of Ionic 3 and can be fixed by adding the following CSS style:
.scroll-content {
padding-bottom: 0 !important;
}
I have had similar issues and this piece of CSS fixed it.
When an input is focused, Ionic adds some padding to the bottom of the scroll-content class, to create room for the keyboard.
Update
Relative top positioning may cause the issue (as well).
This person's answer helped me"
https://stackoverflow.com/a/61337530/10661436
Basically just go to your AndroidManifest.xml file,
search for:
android:windowSoftInputMode=ABC
Replace "ABC" with adjustPan
Just add this to your config.xml and make sure you have your keyboard plugin installed.
<preference name="KeyboardResizeMode" value="ionic" />

JQuery Class selector not working on Zoom plugin

I've been trying to get jQuery to select a particular element in the JQuery zoom plugin but it doesnt seem to be working
This is the html markup for the zoom region
<div class="zoom" style="width: 60% !important; display: block; position: fixed; overflow: hidden;">
<img src="//cdn.shopify.com/s/files/1/0456/6809/t/3/assets/bx_loader.gif?27021" alt="" class="abs-center-translate loader">
<img src="//cdn.shopify.com/s/files/1/0456/6809/products/568A.jpeg?v=1413437903" class="zoomImg" style="position: absolute; top: -1385.54456824513px; left: -389.68108776267px; opacity: 1; width: 682.5px; height: 1024px; border: none; max-width: none; max-height: none;">
</div>
function showZoomImgSmaller(img) {
var zoomsmall = $('.zoom');
zoomsmall.empty();
zoomsmall.append('{{ "bx_loader.gif" | asset_url | img_tag: "", "abs-center-translate loader" }}');
$('.collectionZoomContainer').show();
zoomsmall.attr( "style","width:60%!important" );
var zoomsmallimg= $('.zoom > img');
console.log(zoomsmallimg.next().get());
$('.zoomImg').attr("style","max-width:500px!important");
zoomsmall.show();
zoomsmall.zoom({url: img, magnify: 0.5});
}
The console returns just a [] for the .zoomImg.get() and an undefined for a .zoomImg.html()
I want to change the css of this particular element and can only do it through jquery.
Any help will be greatly appreciated. Thanks
There is a lot going on here that I cannot see, but my guess is that when you call empty() on your div, you are removing all children of the div (including the .zoomImg class which you are trying to look up later). Instead of removing all elements, you might just want to remove the first image:
function showZoomImgSmaller(img) {
var zoomsmall = $('.zoom');
$('.zoom > .loader').remove(); //change is here
zoomsmall.append('{{ "bx_loader.gif" | asset_url | img_tag: "", "abs-center-translate loader" }}'); //angular? not sure what this does
$('.collectionZoomContainer').show(); //not sure what this
zoomsmall.attr( "style","width:60%!important" );
var zoomsmallimg= $('.zoom > img');
console.log(zoomsmallimg.next().get());
$('.zoomImg').attr("style","max-width:500px!important");
zoomsmall.show();
zoomsmall.zoom({url: img, magnify: 0.5});
}
Hey so I managed to get my style applied by appending css in the head of the page. This style was applied even though the element didnt exist till later.
This is the code I used.
$("<style type='text/css'> .zoomImg{ max-width:200px!important;} </style>").appendTo("head");
Cheers.

change class attributes when hovering over other css class

I am trying to give a div with class "left2" a border-radius when class "left1_sub" is hovered.
I´ve searched a lot of solutions, but nothing seems to work for me.
The html to it: http://web318.login-11.hoststar.at/ben/kleinraum/wp/menuimg/index.html
and the full css: http://web318.login-11.hoststar.at/ben/kleinraum/wp/menuimg/style.css
.left1_sub{
padding-top:2%;
padding-bottom:2%;
width: 100%;
float: left;
background-color: #cccccc
}
.left1_sub:hover ~ .left2 {border-radius: 10px;}
.left2{
float: left;
margin-right: 20px;
margin-top: 20px;
width: 500px;
height:600px;
background-color: #ccccff
}
Just introducing myself to css3 so sorry if there are failures.
ben
This can be done very easily with jQuery or something similar.
If are comfortable using jQuery something like this would work.
First, create a class in CSS with a border radius:
.rounded { border-radius: 5px; /* (or whatever) */ }
Then, in <script> tags:
jQuery(document).ready(function($) {
var obj = $('.left1_sub'),
target = $('.left2');
obj.hover(
//mouse in
function(){
target.addClass('rounded');
//mouse out
},function(){
target.removeClass('rounded');
});
});
http://jsfiddle.net/wGzgB/11/