Append Button at the end of Multi-Line Text - ios

I have a multiline text with info button at the end of the text which is done with HStack at the moment.
HStack(spacing: 15) {
Image(uiImage: "questionMark")
.resizable()
.scaledToFit()
.frame(width: 15, height: 15)
Text("Neque porro quisquam est qui dolorem ipsum quia dolor sit amet.")
.fixedSize(horizontal: false, vertical: true)
}
which looks like this:
Goal:
But I want to have the button at the end of the last text like infoIcon should appear right after ipsum.
Note:
What could be the best solution to achieve this and would like not to use UIKit in this regards?

The possible solution is to add use Image constructor of Text but you can not add action only the image.
Like this
struct ContentView: View {
var body: some View {
fullImageText
.onTapGesture {
}
}
var fullImageText: Text {
Text("Neque porro quisquam est qui dolorem ipsum quia dolor sit amet.") + Text(Image("edit"))
}
}
Another solution is to use NSMutableAttributedString wrap with UIViewRepresentable. Here is demo : https://stackoverflow.com/a/62169577/14733292

Related

How to stop SwiftUI section in List from flickering?

Explanation of Problem:
New beginner in iOS SwiftUI here! I am currently building a list with a toggle and some text.
Unfortunately each time the toggle has its binary value changed - the list flashes briefly. How do I solve this issue?
Animated Screenshot:
Current SwiftUI Code:
ForEach(models, id: \.self)
{ model in
VStack(alignment: .leading, spacing: 1)
{
Toggle("Lorem ipsum dolor sit amet", isOn: model.enabled.didSet
{ isOn in
model.doSomeLogicWithThis(enabled: isOn)
})
if model.hasDescr
{
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.").multilineTextAlignment(.leading).foregroundColor(.gray).font(.footnote)
}
}
}

SwiftUI animation/transition within scrollview behaving strange

I have a ScrollView in SwiftUI with multiple elements, some of them expands on tap.
struct ExpandingView: View {
#State var showContent = false
var body: some View {
VStack {
HStack {
Button(action: {withAnimation {
self.showContent.toggle()
}
}) {
Image(systemName: "chevron.right.circle")
}
Text("TITLE")
.padding(.leading, 10)
Spacer()
}
if showContent {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras volutpat dapibus ante eget laoreet. Aenean lacus elit, auctor ut nisl id, fermentum pretium mi. Quisque lacus nisl, suscipit hendrerit est sed, congue dictum augue. Suspendisse semper viverra accumsan. Maecenas commodo turpis convallis nisl bibendum pharetra.")
.transition(AnyTransition.move(edge: .top).combined(with: .opacity))
}
}
}
}
struct Test: View {
var body: some View {
ScrollView {
ExpandingView()
ExpandingView()
ExpandingView()
Text("Some static text")
}
}
}
If you try to open one of the expanding texts, you will see that the transition is not smooth, it kind of like jumps and then the transition starts.
So here is what I've tried:
If I remove the scrollview and put this to VStack for example it is working fine, but that is not an option because I have much more elements which will not fit on the screen.
I've tried to set an animation for the scrollview because I read that it solves this kind of problem, like this:
ScrollView {
ExpandingView()
ExpandingView()
ExpandingView()
Text("Some static text")
}.animation(.spring())
It works fine in terms of the opening transition, it even looks better with the spring effect, but the spring animation for the whole scrollview plays when the view appears, which I don't want.
Again, if I change the ScrollView to a VStack, the animation does not play on appearing which is nice, but I have to use a scrollview. So the best solution for me would be to keep the animation for opening the texts, but somehow remove it when the view appears.
Here is possible solution. Read also comments inline. Tested with Xcode 11.4 / iSO 13.4
struct ExpandingView: View {
#State var showContent = false
var body: some View {
VStack {
HStack {
Button(action: {
self.showContent.toggle()
}) {
Image(systemName: "chevron.right.circle")
}
Text("TITLE")
.padding(.leading, 10)
Spacer()
}
if showContent {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras volutpat dapibus ante eget laoreet. Aenean lacus elit, auctor ut nisl id, fermentum pretium mi. Quisque lacus nisl, suscipit hendrerit est sed, congue dictum augue. Suspendisse semper viverra accumsan. Maecenas commodo turpis convallis nisl bibendum pharetra.")
.fixedSize(horizontal: false, vertical: true)
.transition(AnyTransition.move(edge: .top).combined(with: .opacity))
}
}
}
}
struct DemoExpandingView: View {
// initial nil to avoid initial animation
#State private var animation: Animation? = nil
var body: some View {
ScrollView {
VStack {
ExpandingView()
ExpandingView()
ExpandingView()
Text("Some static text")
}.animation(animation) // << needed to animate static section
}
.onAppear {
DispatchQueue.main.async {
// assign in-container animation `after` container rendered
self.animation = .default
}
}
}
}

jsPDF fromHTML in Angular: addImage does not support files of type 'UNKNOWN'

I know there are other issues with the error "addImage does not support files of type 'UNKNOWN'", but the difference is that I'm not using addImage directly, but fromHTML to convert an HTML that contains images in an Angular 5+ app.
Curiosly, the images by themselves are not the problem, because they are successfully converted to PDF in this fiddle which uses simple jQUery instead of Angular. So the problem lays in the NPM version of the jsPDF code. Maybe that version of the code does not support images in formats other than PNG?
In this particular case, I don't have control over the images, I only need grab the HTML section and convert it to PDF.
The error message is:
ERROR Error: addImage does not support files of type 'UNKNOWN', please ensure that a plugin for 'UNKNOWN' support is added.
at Object.x.addImage (jspdf.min.js:50)
at k (jspdf.min.js:202)
at jspdf.min.js:202
at l (jspdf.min.js:202)
at Image.i.onerror.i.onload (jspdf.min.js:202)
at Image.wrapFn (zone.js:1188)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:16147)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)
The TS code is:
#ViewChild('content') recipeView: ElementRef;
downloadPDF() {
const doc = new jsPDF();
const specialElementHandlers = {
'#editor': function (element, renderer) {
return true;
}
};
const content = this.recipeView.nativeElement;
doc.fromHTML(content, 15, 15, {
'width': 190,
'elementHandlers': specialElementHandlers
}, (dispose) => {
doc.save('test.pdf');
});
}
<div class="row" #content>
<h1>The Title</h1>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eos, modi dolores? Aliquam cum fuga vero velit! Vel
temporibus natus quasi accusantium! Recusandae quaerat qui exercitationem, debitis omnis deserunt dolorem non.</p>
<br />
<img src="http://a5.mzstatic.com/eu/r30/Purple3/v4/3d/57/31/3d573127-31d5-e4a9-9f8e-986c4616d467/icon175x175.png"
alt="" width="175" height="175">
<img src="https://http2.mlstatic.com/corte-para-hallacas-produccion-nacional-60-unidades-para-60-D_NQ_NP_869908-MLA25589543992_052017-F.webp"
alt="" width="175" height="175">
<img src="https://4.bp.blogspot.com/-C-PxcAwhHXo/WlWDzAmHB7I/AAAAAAAAG8k/hblgAA_HrIIYW_VPzVNuXb7ZjFnxKpduwCLcBGAs/s1600/como-hacer-empanadas-venezolanas.jpg"
alt="" width="175" height="175">
<br />
</div>
<button class="btn" (click)="downloadPDF()">PDF</button>

Angular Material: mat-checkbox vertical alignment of checkbox

I can't seem to override the defaults to vertically align the checkbox relative to the checkbox label. Searched for a while but nothing has worked. See example image:
Should be like:
Have tried the following:
.mat-checkbox-inner-container {
margin: none;
}
HTML:
<label><b>Home Type</b></label>
<mat-checkbox>Entire place<br><small class="text-muted">Have a place to yourself</small></mat-checkbox>
<mat-checkbox>Private room<br><small class="text-muted">Have your own room and share some common spaces</small></mat-checkbox>
<mat-checkbox>Shared room<br><small class="text-muted">Stay in a shared space, like a common room</small></mat-checkbox>
Similar to Craig's answer but as a descendant of .mat-checkbox.mat-accent to spare the need of using "!important"
.mat-checkbox.mat-accent .mat-checkbox-inner-container {
margin: 2px 8px auto 0;
}
or using sass/less
.mat-checkbox.mat-accent {
.mat-checkbox-inner-container {
margin: 2px 8px auto 0;
}
}
Just run into the same problem. I used the following to solve it (unfortunately needs the dreaded !important):
.mat-checkbox-inner-container {
margin: 2px 8px auto 0 !important;
}
I found I had to adjust the top margin (2px in this case) to get the layout beside the label to look correct.
I was able to achieve this (I'm using Angular/Material 7.x) by resetting the margins the checkbox container uses.
Note that I have had to apply an additional translateY to account for the box's border-width, and reset the wrap on the label so the text doesn't try to stay on one line.
your.component.scss
:host {
::ng-deep {
.mat-checkbox-inner-container {
margin-top: initial;
margin-bottom: initial;
transform: translateY(2px); // value of checkbox border-width
}
.mat-checkbox-label {
white-space: normal; // wrap label text
}
}
}
StackBlitz Fiddle
I know this is old, but below worked for me – I honestly didn't even know auto worked with vertical alignment, but I guess it does 🤷🏽‍♂️:
.mat-checkbox-inner-container {
margin-top: 0;
}
<div>
<h1>LABEL CHECKBOX</h1>
<mat-checkbox class="mat-checkbox-layout"><strong>FINE</strong>Lorem ipsum dolor sit amet consectetur adipisicingelit. Optio vitae molestiae nemo magni odio voluptate corporis veniam sapiente earum fugiat rem,maiores et placeat qui iure, nobis ipsam sintenim.</mat-checkbox>
<mat-checkbox class="mat-checkbox-layout"><strong>OK</strong>Lorem ipsum dolor sit amet consectetur adipisicing elit.Optio vitae molestiae nemo magni odio voluptate corporis veniam sapiente earum fugiat rem, maiores et placeat qui iure, nobis ipsam sintenim.</mat-checkbox>
</div>
And the CSS is this (I create css class identically with angular css class)
.mat-checkbox-layout {
text-align: justify;
}
::ng-deep .mat-checkbox-layout .mat-checkbox-layout {
white-space: normal !important;
}
:host {
::ng-deep {
.mat-checkbox-layout {
align-items: end!important;
}
.mat-checkbox-label {
white-space: normal; // wrap label text
}
}
}
There is a fast solution which is not related to ng-material
you can put your "mat-checkbox" into "li" element and align your "ul" by setting the number of columns like this:
<ul style="columns:2">
<li>
<mat-checkbox>Entire place<br><small class="text-muted">Have a place to yourself</small></mat-checkbox>
</li>
<li>
<mat-checkbox>Private room<br><small class="text-muted">Have your own room and share some common spaces</small></mat-checkbox>
</li>
<li>
<mat-checkbox>Shared room<br><small class="text-muted">Stay in a shared space, like a common room</small></mat-checkbox>
</li>
</ul>

jquery for restricting words to be displayed

im trying to restrict 120 characters to be displayed.while the rest should be represented as "(more..)".which is make clickable to view the entire content.when i enter desc with space..the "(more..)" moves to the second..if i dont use space...it moves to the first line.
<h:outputScript>interaction360();
function interaction360(){
$(document).ready(function(){
var maxLength = 120;
$(".show-read-more").each(function(){
var myStr = $(this).text();
if($.trim(myStr).length > maxLength){
var newStr = myStr.substring(0, maxLength);
var removedStr = myStr.substring(maxLength, $.trim(myStr).length);
$(this).empty().html(newStr);
$(this).append('<span class="more-text"> (more...) </span>');
}
});
$(".more-text").css("color","blue");
});
}
Live Demo Link : CodePen
HTML code :
<span class="more">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</span>
CSS Code :
.morecontent span { display: none; }
.morelink { display: block; }
jQuery Code:
$(document).ready(function() {
// Configure/customize these variables.
var showChar = 120; // How many characters are shown by default
var ellipsestext = "...";
var moretext = "Show more ...";
var lesstext = "Show less";
$('.more').each(function() {
var content = $(this).html();
if(content.length > showChar) {
var c = content.substr(0, showChar);
var h = content.substr(showChar, content.length - showChar);
var html = c + '<span class="moreellipses">' + ellipsestext+ ' </span><span class="morecontent"><span>' + h + '</span> ' + moretext + '</span>';
$(this).html(html);
}
});
$(".morelink").click(function(){
if($(this).hasClass("less")) {
$(this).removeClass("less");
$(this).html(moretext);
} else {
$(this).addClass("less");
$(this).html(lesstext);
}
$(this).parent().prev().toggle();
$(this).prev().toggle();
return false;
});
});
Hope it will work for you.

Resources