I am populating a textfield programmatically and scrolling to the maxScrollH as the new text is added so the user can see the progression of text. This works fine, until I click the TextField, which sets scrollH back to 0 and places the caret in the text at the equivalent position.
textField.setSelection( text.length, text.length ); //sets the caretIndex/selection to the end
textField.scrollH = textField.maxScrollH; //scrolls to max
this is the code that I am using to scroll when the textField text property is updated. I've tried adding a listener to the click event on the textField, which works in a way, but causes a visible jump.
override protected function createChildren() : void
{
super.createChildren();
textField.addEventListener(MouseEvent.CLICK, handleTextFieldClick, false, 0, true);
}
protected function handleTextFieldClick(event:MouseEvent):void
{
textField.scrollH = currentTextFieldScrollPosition; //stored scrollH value
trace(textField.scrollH);
}
My guess is that there is a scroll position being calculated or stored someplace that I can't find.
The flex TextInput sets the selection of the textField:
/**
* #private
* Gets called by internal field so we draw a focus rect around us.
*/
override protected function focusInHandler(event:FocusEvent):void
{
if (event.target == this)
systemManager.stage.focus = TextField(textField);
var fm:IFocusManager = focusManager;
if (editable && fm)
{
fm.showFocusIndicator = true;
if (textField.selectable &&
_selectionBeginIndex == _selectionEndIndex)
{
textField.setSelection(0, textField.length);
}
}
[...]
overriding this in my component fixes this problem:
override protected function focusInHandler(event:FocusEvent):void
{
super.focusInHandler(event);
textField.scrollH = currentTextFieldScrollPosition;
}
Turns out you need to make an onclick handler for the window with the UIScrollbar, and then add a focus out event listener for it that passes the scrollbar location at the time of the onclick to the focus.
ActionScript 3: maintaining textarea UIscrollbar position on loss of focus in flash embed
Related
I have implemented a custom clickable label class in Xamarin.Forms along with a custom renderer, that adds a RippleDrawable as the controls Foreground. I am creating the RippleDrawable with the following code:
public static Drawable CreateRippleDrawable(Context context)
{
var typedValue = new TypedValue();
context.Theme.ResolveAttribute(Resource.Attribute.SelectableItemBackground, typedValue, true);
var rippleDrawable = context.Resources.GetDrawable(typedValue.ResourceId, context.Theme);
return rippleDrawable;
}
In my custom renderer I assign the drawable
this.Control.Foreground = DrawableHelper.CreateRippleDrawable(this.Context);
and update the ripple when the user touches the control
private void LinkLabelRenderer_Touch(object sender, TouchEventArgs e)
{
if (e.Event.Action == MotionEventActions.Down)
{
this.Pressed = true;
}
if (e.Event.Action == MotionEventActions.Cancel)
{
this.Pressed = false;
}
if (e.Event.Action == MotionEventActions.Up)
{
this.Ripple.SetHotspot(e.Event.GetX(), e.Event.GetY());
this.Pressed = false;
// raise the event of the Xamarin.Forms control
}
}
Now, whenever I click the control, the ripple will be shown, which is the expected behavior, but if I touch (tap or long-press) the parents of the control (e.g. the StackLayout, Grid or whatever layout contains the label, including their parent Layout, Page or View) the ripple animation will be triggered. Anyway, the event handler LinkLabelRenderer_Touch in not called in this case, only when the actual control is touched.
I can work around this behavior by adding an empty GestureRecognizer to the respective parent(s), but I really dislike this solution, because this is but a hack. And to make things worse it is a hack I'll always have to remember whenever I use the control.
How can I prevent the RippleDrawable being shown when the parent is touched?
Turned out I got things fundamentally wrong. Subscribing the Touch event is not the way to go. I had to make the control clickable and subscribe the Click event
this.Control.Clickable = true;
this.Click += LinkLabelRenderer_OnClick;
There is no need to handle all that RippleTouch stuff the way I did (via the Touch event) but could let android handle things for me.
I have a MX TextInput field on my form. As one of our user has seizure problems with blinking cursors, I am trying to disable it but without success. Through Control Panel, I have been able to prevent a blinking cursor in Office Apps and on the Web browsers but not with the Flex Application which uses the Flash Player. Has anyone come across this issue and have a solution?
Here's a simple solution that removes the cursor all together. I'm not sure if you want to remove the cursor (feasible) or stop the cursor from blinking (seems less feasible).
It works by setting the underlying TextField object's selectable property to false. The MX TextInput class has it's own selectable property, however, the code in TextInput also requires the editable property to be false to disable selection. So you need to extend TextInput to work around that.
The underlying TextField doesn't expose any properties to stop the cursor from blinking (that I'm aware of). TextField is one of Flash Player's built in classes, so the chances of modifying this low level behavior seem slim.
This obviously breaks the ability to copy/paste in the TextInput. You might have to devise a way to temporarily enable selection to support copy/paste or selecting text in general.
package
{
import mx.controls.TextInput;
public class CustomTextInput extends TextInput
{
public function CustomTextInput()
{
}
private var _hideCursor:Boolean = true;
private var hideCursorChanged:Boolean = true;
public function get hideCursor():Boolean
{
return _hideCursor;
}
public function set hideCursor(value:Boolean):void
{
if (value == hideCursor)
{
return;
}
hideCursorChanged = true;
_hideCursor = value;
invalidateProperties();
}
override protected function commitProperties():void
{
super.commitProperties();
if (hideCursorChanged)
{
hideCursorChanged = false;
textField.selectable = !_hideCursor;
}
}
}
}
I have made a hierarchy in which there is a main page, using add element i have attached a component mxml of type group. There is a single button on main page when clicked it should add children of type group in that group type mxml component along with two buttons. Now using one of buttons i am attaching another component mxml type group. the problem is even they overlap i can still excess the children groups of first group component mxml. how can i stop this mouse events to happen.
I think those kind of events usually bubble up to parent components.
You can try using the following code in your mouse click event listener to stop further propagation:
private function onMouseClicked(event: MouseEvent): void {
event.stopPropagation();
... do whatever you wanted when smth was clicked ...
}
By setting enabled, mouseChildren, mouseEnabled to false, you will disable the entire component and it's children. example below
private var myPreviousGroupComponent:Group = null;
function addNewGroup():void
{
if(myPreviousGroupComponent != null)
{
myPreviousGroupComponent.enabled = false;
myPreviousGroupComponent.mouseChildren = false;
myPreviousGroupComponent.mouseEnabled = false;
}
var newGroup:Group = new Group();
addElement(newGroup);
myPreviousGroupComponent = newGroup;
}
I'm trying to use a flexlib schedule viewer in my application.
I want to have it so that when I click on a scheduled event, it calls a function in my main app (that will allow me to edit the event). But there doesn't seem to be any specific function for anything like this built into the class ie no event dispatched when I click on an event.
I can use the 'click' function to detect that the item has been clicked on.. and have tried something like this:
private function exerciseClickHandler(event:MouseEvent):void{
if (exerciseSeries.selectedItem != null){
//code
}
}
<code:ScheduleViewer id="exerciseSeries" click="exerciseClickHandler(event)" />
This method isn't very reliable because if it only works the first time.. once an item is selected, it stays selected so all following clicks on the item fulfills the condition.
Is there any way to determine whether an event was being clicked on?
Or do I have to extend the component and add some sort of clickEvent when an event is clicked on.
Since exerciseClickHandler is firing up when you click on the component, wouldn't this work?
Instead of
private function exerciseClickHandler(event:MouseEvent):void{
if (exerciseSeries.selectedItem != null){
//code
}
}
write
private function exerciseClickHandler(event:MouseEvent):void{
switch (exerciseSeries.selectedItem)
{
//code
case xy:
break;
}
}
or
private function exerciseClickHandler(event:MouseEvent):void{
//do something with exerciseSeries.selectedItem
}
What I mean is that you wrote that everything stops after the first element is clicked. And according to the code you provided it has to stop, beacuse after the first click exerciseSeries.selectedItem won't be null anymore, since it's selected. So remove the conditional you wrote and use the instance.
I'd suggest you set up a ChangeWatcher to keep an eye on the selectedItem (or selectedItems if you are going to allow multiple selection at some point). Example:
protected exerciseSeriesCreationCompleteHandler(event:FlexEvent):void{
ChangeWatcher.watch(this,['exerciseSeries','selectedItem'], handleChange_SelectedItem);
}
protected function handleChange_SelectedItem(event:PropertyChangeEvent):void{
// Either
dispatchedEvent(//some custom event);
// Or
someDirectMethodCall();
}
An alternative would be to search for an instance of the the event class in the view hierarchy under the mouse coordinates whenever a user clicks.
//Attach this click handler to the component
private function handleClick(event : MouseEvent) : void {
var obj : *EventClass*= null;
var applicationStage : Stage = FlexGlobals.topLevelApplication.stage as Stage;
var mousePoint : Point = new Point(applicationStage.mouseX, applicationStage.mouseY);
var objects : Array = applicationStage.getObjectsUnderPoint(mousePoint);
for (var i : int = objects.length - 1; i >= 0; i--) {
if (objects[i] is *EventClass*) {
obj = objects[i] as *EventClass*;
break;
}
}
if(obj is *EventClass*){
//Dispatch some custom event with obj being the item that was clicked on.
}
}
Where EventClass is the class of the objects that represent events
I have had similar problems and sometimes you can get by with wrapping the object with a Box and putting the click event on the Box. If you have not already tried that, it's a cheap, easy fix (if it works for you).
<mx:Box click="exerciseClickHandler(event)">
<code:ScheduleViewer id="exerciseSeries" />
</mx:Box>
Rather than assign to every buttons with MouseEvent, I assign to AIR application with:
private function init():void {
this.addEventListener(MouseEvent.MOUSE_DOWN,mpressKey);
}
However, I only want the mouse_down to execute if it detect a "button" property instead of Demo0.WindowedApplicationSkin2.Group3.contentGroup.g4 (g4 is an id).
Don't rely on event.target to check if a button was clicked or not. The target property is set to the innermost item that was clicked on. When you click on a button, you're not always clicking on The Button; you might be clicking on the text field that displays the label, or the background image if any, or some other child skinning part etc - the target will be set to this inner item.
If you want to have a single click handler for all buttons and take appropriate action based on the button clicked, you can assign same function as handlers for each button and check the event.currentTarget property; when an event handler is invoked, currentTarget is set to the object with which that handler was registered.
btn1.addEventListener(MouseEvent.CLICK, clickHandler);
btn2.addEventListener(MouseEvent.CLICK, clickHandler);
btn3.addEventListener(MouseEvent.CLICK, clickHandler);
public function clickHandler(e:MouseEvent):void
{
if(e.currentTarget == btn1){
/* Handle btn1 here */
}
else if(e.currentTarget == btn2){
/* Handle btn1 here */
}
else if(e.currentTarget == btn3){
/* Handle btn1 here */
}
}
When you add a single mouse handler using airApp.addEventListener, the currentTarget will always be your airApp and thus you can't use it to act as a single function to handle them all.
Are you asking how to test to see if the target is a Button, or a particular button?
If it's a Button
if ( e.target is Button ) { ... }
or if it's a particular button
if ( e.target == myButton ) { ... }