In order to manage automatic scrolling in a content editable UIWebView, I need to get the correct caret Y vertical coordinate.
I identified two methods, using javascript.
The first one uses getClientRects javascript function:
CGRect caretRect = [self.webView stringByEvaluatingJavaScriptFromString: #"
var sel = document.getSelection();
var range = sel.getRangeAt(0).cloneRange();
range.collapse(true);
var r =range.getClientRects()[0];
return '{{'+r.left+','+r.top+'},{'+r.width+','+r.height+'}}';"];
int caretY = caretRect.origin.y;
With this, the caret keeps blinking and one gets its correct vertical position with one problem: when user type return key, so that the next line is empty, caretY is equal to zero until a character key is typed. So that this method cannot be use.
The second one insert a tmp span, then removes it:
int caretY = [[self.webView stringByEvaluatingJavaScriptFromString: #"
var sel = window.getSelection();
sel.collapseToStart();
var range = sel.getRangeAt(0);
var span = document.createElement(\"span\");
range.insertNode(span);
var topPosition = span.offsetTop;
span.parentNode.removeChild(span);
topPosition;"] intValue];
This gives the correct caretY in any situation. But the caret stops blinking, which is very unhelpful to see it on the screen.
Does anybody knows any method (or adaptation of these) that can make the following:
- get the correct caret Y in any situation
- keep the caret blinking in any situation
Thanks
Not sure if this is too late; the following works for me.
Add getCaretY() below to your js file:
function getCaretY() {
var y = 0;
var sel = window.getSelection();
if (sel.rangeCount) {
var range = sel.getRangeAt(0);
if (range.getClientRects) {
var rects = range.getClientRects();
if (rects.length > 0) {
y = rects[0].top;
}
}
}
return y;
}
Then call it from obj-c file as below:
NSString *yPos = [webView stringByEvaluatingJavaScriptFromString:#"getCaretY()"];
Related
I am trying to render string using the CoreText api. Each character is rendered in the CAShapeLayer and i am getting the layer offset (x coordinate) for each character like this:
let offset = CTLineGetOffsetForStringIndex(line, glyphIndex, nil)
But the resulting offset doesn't seem to respect kerning between letters. Here is a an image of what i mean - the top label is a UILabel, the bottom one is my custom rendering:
As you can see the "A" letter in my custom label is placed further from the "W" letter.
I would really appreciate any help.
Thanks in advance.
In case someone has the same problem, i used an approach from this place: https://github.com/MichMich/XMCircleType/blob/master/XMCircleType/Views/XMCircleTypeView.m, the kerningForCharacter function. Here is the function itself:
- (float)kerningForCharacter:(NSString *)currentCharacter afterCharacter:(NSString *)previousCharacter
{
//Create a unique cache key
NSString *kerningCacheKey = [NSString stringWithFormat:#"%#%#", previousCharacter, currentCharacter];
//Look for kerning in the cache dictionary
NSNumber *cachedKerning = [self.kerningCacheDictionary objectForKey:kerningCacheKey];
//If kerning is found: return.
if (cachedKerning) {
return [cachedKerning floatValue];
}
//Otherwise, calculate.
float totalSize = [[NSString stringWithFormat:#"%#%#", previousCharacter, currentCharacter] sizeWithAttributes:self.textAttributes].width;
float currentCharacterSize = [currentCharacter sizeWithAttributes:self.textAttributes].width;
float previousCharacterSize = [previousCharacter sizeWithAttributes:self.textAttributes].width;
float kerning = (currentCharacterSize + previousCharacterSize) - totalSize;
//Store kerning in cache.
[self.kerningCacheDictionary setValue:#(kerning) forKey:kerningCacheKey];
//Return kerning.
return kerning;
}
i am new in cocos2d-js here, i just created this code:`
var that = this;
that._dice
// add player
// create sprite sheet
cc.spriteFrameCache.addSpriteFrames(res.dice_plist);
var spriteSheet = new cc.SpriteBatchNode(res.diceRed_png);
that.addChild(spriteSheet, 2);
// init runningAction
var animFrames = [];
for (var i = 1; i < 7; i++) {
var str = "dieRed" + i + ".png";
var frame = cc.spriteFrameCache.getSpriteFrame(str);
animFrames.push(frame);
}
var animation = new cc.Animation(animFrames, 0.1);
that.runningAction = new cc.Repeat.create(new cc.Animate(animation), Math.random()*10);
var diceSprite = new cc.Sprite("#dieRed1.png");
diceSprite.visible = true;
console.log(this.getContentSize(diceSprite));
diceSprite.runAction(this.runningAction);
that._dice.push(diceSprite);
var size = cc.winSize;
spriteSheet.setPosition(size.width/6.5, size.height/1.20);
spriteSheet.setAnchorPoint(0.5, 0.5);
spriteSheet.addChild(diceSprite, 2);
`
and i would like to use the getFrames() feature to return the array of ccanimation frames. i'm just thinking to get the information of which picture are being animated on the screen there, for example, if the #dieRed1.png is being animated or visible on the screen, it would show value or return value of 1. i have tried to googled around and cannot find any other clue there. if there is any better method, i would love to see that as well. sorry for the english anyway, a bit confused how to arrange the words. thank you :)
Ok, so refering to
the official docs
{Array} getFrames()
Returns the array of animation frames
Which means you can just do:
var frames = animation.getFrames();
To get the array. And then you'll receive an array of cc.AnimationFrame.
To get sprite link do:
var frame = frames[0];//cc.AnimationFrame
var spriteFrame = frame.getSpriteFrame(); //cc.SpriteFrame
var texture = spriteFrame.getTexture(); // cc.Texture
And the texture itself should have the name attribute which may do the job.
In my actionscript 3 i have a textfield, which i fill with the messages (get them from the webservice). Not all the messages are visible, so every (for Example) 5s i'm moving them vertically to the top.
To do that, i'm using the Tween effect, but the thing is, that it moves only the visible text and not the rest text together (the invisible one).
When scrolling - i can see the rest text.
Image to show the situation (Sorry for my skills):
Here are some code: Function to fill messages object. Plus count how many lines every message will take to display ( so i could easilly use the tween effect (From - to))
private function getNewMsg(e:ResultEvent):void
{
size = e.result.toString().split(" ").length - 1;
for (var i=0; i<size; i++)
{
smsList.push(new smsItem(e.result[i].Id, e.result[i].text));
}
summ = 0;
for (var d=0; d<size; d++)
{
textfield.appendText(smsList[d].Text.toUpperCase()+'\n');
if (d >= 1)
{
smsList[d].Lines = textfield.numLines - summ;
summ += smsList[d].Lines;
}
else
{
smsList[d].Lines = textfield.numLines-1;
summ += smsList[d].Lines + 1;
}
}
twEnd = smsList[1].Lines * (-30.5);
}
And on timer i'm starting the Tween:
function timerHandler(e:TimerEvent):void
{
myTweenX = new Tween(textfield, "y", None.easeIn, twStart, twEnd, 4, true)
myTweenX.addEventListener(TweenEvent.MOTION_FINISH, tweenCompleted);
}
function tweenCompleted(e:TweenEvent):void
{
twInd++;
twStart = twEnd;
twEnd += smsList[twInd].Lines * (-30.5);
}
Found the problem. Because of my fixed textfield height, text wasn't. After made the textfields height auto size, evrything got fixed.
I am using TabStrip on a project of mine. The tabstrip has TTTabItems that are the alphabet A-Z. When I click to each alphabet letter the delegate navigates to another page.
In the other page there is a TTTabstrip also (same construction, frame etc). How can I mark the alphabet also on the second tabstrip without triggering the event?
I tried to get the integer value of the letter mod the integer value of "a" (so that it will bring me an index) and assign it to selectedIndex:
unichar letter = [[NSString stringWithString:#"e"] characterAtIndex:0];
/*(k is #"a" unichar)*/
tabBar.selectedTabIndex = letter % kEnglishAlpha;
But it gives me deallocation error.
** UPDATE **
on the drill down detail view (where I have the problem) I mentioned in the comments I have the following coming from a tt navigation:
tt://listWords/Cat
on the view did load event, and after the initialization of the TTTabStrip (that contains only TTTabItem with letters A-Z) and the tabBar.delegate = self declaration, I use the upper code to "select" the chosen letter. The rest of the view shows the definition and everything related. Normally that would be the case, but when I use the back button to return to the view that has the tttableItems (cat, catsup, catnip etc) it says deallocated controller.
My guess is that using the tabselected delegation code and setting a tabindex, it triggers the tab selected code immediate and that's where the problem is. If I don't use the selectedTabIndex code, I can navigate back and through the letters without problem.
There's no function to auto selected a TTTabItem in TTStripTab.
You will have to extend TTTabStrip and add this function:
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)setSelectedTabIndexToCenter:(NSInteger)selectedTabIndex {
if (selectedTabIndex>_tabItems.count-1) {
selectedTabIndex = _tabViews.count-1;
}
[self layoutSubviews];
float horizontalOffset = 0.0f - _scrollView.size.width/2;
for (int i = 0; i < selectedTabIndex; ++i) {
TTTab* tab = [_tabViews objectAtIndex:i];
if (selectedTabIndex-1==i) {
horizontalOffset += tab.size.width*1.5;
} else {
horizontalOffset += tab.size.width;
}
}
if (horizontalOffset<0) {
horizontalOffset = 0;
}
_scrollView.contentOffset = CGPointMake(horizontalOffset, 0);
[super setSelectedTabIndex:selectedTabIndex];
}
This function will select a specific tab item and center on it by changing the offset of the strip tab.
Is it possible to give move effect on a UITextField.
var aminolabel:UITextField;
var aminoLabelMove:Move = new Move(aminolabel);
aminoLabelMove.xFrom = 0;
aminoLabelMove.xTo = 100
aminoLabelMove.duration = 1300;
aminoLabelMove.play();
UITextField could not have animations like move. Which internally calls transformX, transformY. Can have Face effect animation.
Solution
Add UITextField instance to a UIComponent and apply the move effect to the UIComponent.
Example
var aminolabel:UITextField;
var aminoLabelUI:UIComponent;
aminoLabelUI.addChild(aminolabel);
var aminoLabelMove:Move = new Move(aminoLabelUI);
aminoLabelMove.xFrom = 0;
aminoLabelMove.xTo = 100
aminoLabelMove.duration = 1300;
aminoLabelMove.play();