How to align AttributedText ? - xamarin.ios

I have an UITextView containing attributed text.
I'm trying to center it (because the text is attributed, textView.TextAlignment doesn't work).
How can I do ?
I tried this :
var attributes = new CTStringAttributes() { };
var paragraphStyleSettings = new CTParagraphStyleSettings() { Alignment = CTTextAlignment.Center };
attributes.ParagraphStyle = new CTParagraphStyle(paragraphStyleSettings);
textView.AttributedText = attributedString;
But I get the following crash : Foundation.MonoTouchException - NSInvalidArgumentException [NSCFType textBlocks]: unrecognized selector sent to instance ...
So I guess it's not the right way CTParagraphStyleSettings should be used ? But I couldn't find any example of use with Xamarin syntax... How can I set my text's horizontal alignment ?

In Swift you would use the UIKit classes instead of CoreText:
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let attributes = [NSParagraphStyleAttributeName: paragraphStyle, NSForegroundColorAttributeName : UIColor.gray, NSFontAttributeName : UIFont(name: "Helvetica", size: 18)!]
let attributedString = NSAttributedString(string: "some text", attributes: attributes)
I'm not a Xamarin programmer and my c# is rusty but Xamarin has the equivalent functions.

Related

How do you make a text clickable in jetpack compose ? I would also like to toggle it to non clickable after selecting once

Text(
text = "Resend OTP",
fontSize = 20.sp,
color = Textfieldcolor,
style = TextStyle(textDecoration = TextDecoration.Underline)
)
//This is my code this text should be selectable once and then be disabled .
You can add the clickable modifier or can use the ClickableText:
var enabled by remember { mutableStateOf(true)}
ClickableText(
text = AnnotatedString(text) ,
onClick = {
if (enabled) {
enabled = false
text = "Disabled"
}
})
Like #Arpit mentioned it would be better to use a TextButton for this purpose.
But if you absolutely want to use Text, You can use following snippet.
#Composable
fun OneTimeClickableText(text : String, onClick : () -> Unit){
var enabled by rememberSaveable{ mutableStateOf(true)}
Text(
modifier = Modifier
.clickable(enabled = enabled) {
enabled = false
onClick()
},
text = text
)
}
That said I this code is strictly for one-time clickable text. I won't recommend using it for something like OTP button; as user won't be able to click it unless they restart your app. You can pull the enabled variable and manage it from outside(e.g. keeping it disabled for certain amount of time rather than permanently).

Getting the width of SVG text with a title on Node

I'm using svg.js and svgdom on Node to generate SVG files. Here's my code:
// set up svg.js and svgdom
const { createSVGWindow } = require('svgdom');
const window = createSVGWindow();
const document = window.document;
const { SVG, registerWindow } = require('#svgdotjs/svg.js');
registerWindow(window, document);
const draw = SVG(document.element).size(100, 100);
// generate SVG text and title
var title = draw.element('title').words('noun');
var text = draw.text('text').add(title);
var width = text.length();
That last line throws TypeError: cannot read property 'style' of null in svgdom/main-require.cjs:3721:38.
This works when I do it in the browser; something about moving to Node and svgdom causes it to fail. Is there another way I can calculate the width of this text element, or a different way to attach the title to the text? (The title is being used to show additional information on hover.) Calling text.width() always returns 0.
I'm using svg.js 3.0.16 and svgdom 0.1.8. Should I open an issue on one of them? If so, which one?

How to use D3 force layout with existing SVG elements as nodes

I have a javascript array of objects where each object has .ui attribute that contains an existing SVG shape/element of various kinds ( a self contained "g" element with others inside ).
I want to arrange these objects as a force graph layout in D3. So, instead of having d3 create circles (or whatever) I want to assign one of my ui objects to the graph.
I have created a simplified fiddle << HERE >> for that. The objects that are pre-existing and should be part of the graph are the 3 colored rectangles. In this example I failed to achieve that. The d3 append command can be used just to construct shapes/elements, but not to append an already constructed one. I was trying to do this, and it cannot work in D3:
node.append( function(d) { d.ui.node(); }) ...
... as mentioned, this wont work as d3 does not append elements.
var svgContainer = d3.select("#svgContainer");
// =============================================================
// creates the SVG elements to be used ( 3 colored rectangles )
// =============================================================
var element0a = svgContainer.append("g").attr("transform","translate(100,100)");
var element0b = element0a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","red");
var element1a = svgContainer.append("g").attr("transform","translate(100,200)");
var element1b = element1a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","green");
var element2a = svgContainer.append("g").attr("transform","translate(100,300)");
var element2b = element2a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","blue");
// =============================================================
// fills up an object array that contains details plus the UI attribute
// =============================================================
var nodeArray = new Array();
nodeArray[0] = { id : "000", label : "label 000", ui : element0a };
nodeArray[1] = { id : "001", label : "label 001", ui : element1a };
nodeArray[2] = { id : "002", label : "label 002", ui : element2a };
// not interested in dealing with the edge/link right now, just empty
var linkArray = new Array();
// =============================================================
// D3 force layout stuff
// =============================================================
var force = self.force = d3.layout.force()
.nodes(nodeArray)
.links(linkArray)
.gravity(.05)
.distance(80)
.charge(-100)
.size([600, 600])
.start();
var node = svgContainer.selectAll("g.node")
.data(nodeArray)
.enter().append("svg:g")
.attr("class", "node")
.call(force.drag);
// HERE (below) COMES THE ISSUE, where you see append("cicle") I want to append the nodeArray's ".ui" element.
node.append("circle") // <---
.attr("class", "node")
.attr("r",10)
.attr("fill","orange")
.call(force.drag);
force.on("tick", function() {
node.attr("transform", function(d) {return "translate(" + d.x + "," + d.y + ")";});
});
Based on advice from Lars Kotfoff :
Working fiddle here
If the elements to be graph-ed already exist, simply skip the enter() D3 phase and use select() or selectAll() based on a common characteristic of your elements ( a class name for instance ).
This is how the element got created ( added a specific class for allowing an isolated selection ):
var element0a = svgContainer.append("g").attr("class","node").attr("transform","translate(100,100)");
var element0b = element0a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","red");
This is thene part of the code replacing the enter() phase
var node = svgContainer.selectAll("g.node")
.data(nodeArray)
.call(force.drag);
This is what was removed
var node = svgContainer.selectAll("g.node")
.data(nodeArray)
.enter().append("svg:g")
.attr("class", "node")
.call(force.drag);
// HERE (below) COMES THE ISSUE, where you see append("cicle") I want to append the nodeArray's ".ui" element.
node.append("circle") // <---
.attr("class", "node")
.attr("r",10)
.attr("fill","orange")
.call(force.drag);
The problem is that you append the elements to svgContainer to create them, thus they are already attached to something.
What I would suggest as a workaround is to store the element properties in a json file and then read the configuration from the json.
There might be something more elegant.

Hide buttons on pagedown

I'm using pagedown on my website right now, and it's awesome so far, the only detail is
it's not a programming-oriented website, so I'd like to remove the 'code' button.
Is there a way I can do it? I tried using CSS to hide the buttons but the html has inline styles "left: xxx" which I can't change using CSS.
Thanks in advance!
If you open up Markdown.Editor.js, and scroll to approximately line 1360 (it varies depending upon which version you're using), you'll see an area with:
group1 = makeGroup(1);
buttons.bold = makeButton("wmd-bold-button", "Bold - Ctrl+B", "icon-bold", bindCommand("doBold"), group1);
buttons.italic = makeButton("wmd-italic-button", "Italic - Ctrl+I", "icon-italic", bindCommand("doItalic"), group1);
group2 = makeGroup(2);
buttons.link = makeButton("wmd-link-button", "Link - Ctrl+L", "icon-link", bindCommand(function (chunk, postProcessing) {
return this.doLinkOrImage(chunk, postProcessing, false);
}), group2);
buttons.quote = makeButton("wmd-quote-button", "Blockquote - Ctrl+Q", "icon-blockquote", bindCommand("doBlockquote"), group2);
buttons.code = makeButton("wmd-code-button", "Code Sample - Ctrl+K", "icon-code", bindCommand("doCode"), group2);
buttons.image = makeButton("wmd-image-button", "Image - Ctrl+G", "icon-picture", bindCommand(function (chunk, postProcessing) {
return this.doLinkOrImage(chunk, postProcessing, true);
}), group2);
So on and so forth. Simply quote out the buttons you don't want.
Alternatively, you can simply leave out the entire wmd-buttons div and only use the editor and preview components.
Search for doClick(buttons.code)in the code and comment it out
If you look at the makeButton function:
var makeButton = function (id, title, XShift, textOp) {
var button = document.createElement("li");
button.className = "wmd-button";
button.style.left = xPosition + "px";
xPosition += 25;
var buttonImage = document.createElement("span");
button.id = id + postfix;
button.appendChild(buttonImage);
button.title = title;
button.XShift = XShift;
if (textOp)
button.textOp = textOp;
setupButton(button, true); // <--- LOOK HERE
buttonRow.appendChild(button);
return button;
};
The true that is being passed in the call of the setupButton function is the isEnabled flag. What I did was just created another makeButton function and put it right under the first one. The only thing that I changed was that isEnabled flag to false. Then I changed to button.code = makeButton(...) to button.code = makeButton2(...).
buttons.code = makeButton2("wmd-code-button", getString("code"), "-80px", bindCommand("doCode"));

MonoTouch - UIButton with custom gradient

Trying to create a custom UIButton in MonoTouch using CGGradientLayer.
Following along with a few tutorials I've found online such as:
http://www.apptite.be/tutorial_custom_uibuttons.php#gradients
So far can't get anything to display, currently just an empty button.
Here's my code which is running from ViewDidLoad:
var gradient = new CAGradientLayer();
gradient.Colors = new MonoTouch.CoreGraphics.CGColor[]
{
new MonoTouch.CoreGraphics.CGColor(115f, 181f, 216f, 1f),
new MonoTouch.CoreGraphics.CGColor(35f, 101f, 136f, 1f)
};
gradient.Locations = new NSNumber[]
{
.5f,
1f
};
gradient.Frame = btnSearch.Layer.Bounds;
btnSearch.Layer.AddSublayer(gradient);
btnSearch.Layer.MasksToBounds = true;
Any ideas what I've missed?
Thank you :)
Seems like that constructor of CGColor accepts RGB values in 0.0f-1.0f float range, not 0-255 integers.
As an alternative, try to set CGColors by UIColors:
gradient.Colors = new MonoTouch.CoreGraphics.CGColor[]
{
UIColor.FromRGB (115, 181, 216).CGColor,
UIColor.FromRGB (35, 101, 136).CGColor
};
BTW, nice blue gradient :)

Resources