One, overview
iOS has been developed, and we often need to use some controls to build our interface. Sometimes the controls that the system gives us do not meet our needs, and we need to encapsulate some of the controls ourselves. Therefore, we need to understand some of the properties of the control base class to facilitate our encapsulation operations. For example, Uikit provides a set of controls: Uiswitch switch, UIButton button, Uisegmentedcontrol segmented control, UISlider slider, Uitextfield text field control,
Uipagecontrol page controls, and so on, the base classes of these controls are uicontrol. Understanding Uicontrol is very helpful for us to encapsulate similar uibutton,uiswitch and so on trigger class controls.
Two, target-action mechanism
The target-action mechanism is a common and important feature of Uicontrol and its derived subclasses compared to the parent class UIView of Uicontrol.
Target-action is a design pattern that translates to "goal-behavior". When we add a click event to a button by code, it is usually handled as follows:
[Button addtarget:self action: @selector (Tapbutton:) forcontrolevents:uicontroleventtouchupinside];
That is, when a button's Click event occurs, the message is sent to target (the self object here), and the corresponding event is handled by the target object's Tapbutton: method.
The basic process can be used to describe:
Note: Images from official documents Cocoa application competencies for Ios–target ActionThat is, when an event occurs, the event is sent to the control object, which is then triggered by the control object to trigger the action action on the target object to finally handle the event.
Therefore, the target-action mechanism consists of two parts: the target object and the behavior selector. The target object specifies the object that eventually handles the event, and the behavior selector is the method that handles the event.
after the touch event arrives at the Uicontrol object (dispatched by the responder chain), in the Uiresponder method (such as Touchbegan:withevent), Uicontrol converts the standard touch event to
A special control event, simply understood, is that Uicontrol encapsulates complex touch events into simple, easy-to-use control events.
For example, when the Uicontrol object is processed, the event that presses the button is encapsulated as a control event instead of judging the entire operation of the touch screen.
Implementation Method :
@interface Lxcontrol:uiview@property (nonatomic,assign) ID target;//where to find the method @property (nonatomic,assign) SEL action;//the method name to execute-(void) AddTarget: (ID) Target action: (SEL) action; @end
#import "Lxcontrol.h" @implementation lxcontrol#pragma mark- -Trigger Method-(void) AddTarget: (ID) Target action: (SEL) action{ _target = target; _action = action;} #pragma mark-the method of allowing external incoming objects to perform external access-(void) Touchesbegan: (Nsset<uitouch *> *) touches withevent: (Uievent *) event{ [self.target performSelector:self.action withobject:@ "123"];} @end
third, the related properties of Uicontrol
related Properties
@property (nonatomic,getter=isenabled) BOOL enabled;
The control is enabled by default. To disable a control, you can set the Enabled property to No, which causes the control to ignore any touch events. When disabled, the control can also display itself in different ways, such as turning gray to be unavailable. Although it is done by a subclass of the control, this property exists in Uicontrol.
@property (nonatomic,getter=isselected) BOOL selected;
When the user selects the control, the Uicontrol class sets its selected property to Yes. Subclasses sometimes use this property to let a control choose itself, or to behave differently.
@property (nonatomic) uicontrolcontentverticalalignment contentverticalalignment;
Controls how the contents of their own are laid out vertically. By default, the content is top-to-bottom, and for text fields, it may be changed to Uicontrolcontentverticalalignmentcenter. For this field, you can use the following values:
1.UIControlContentVerticalAlignmentCenter
2.UIControlContentVerticalAlignmentTop
3.UIControlContentVerticalAlignmentBottom
4.UIControlContentVerticalAlignmentFill
@property (nonatomic) uicontrolcontenthorizontalalignment contenthorizontalalignment;
Horizontal Direction
1.UIControlContentHorizontalAlignmentCenter
2.UIControlContentHorizontalAlignmentTop
3.UIControlContentHorizontalAlignmentBottom
4.UIControlContentHorizontalAlignmentFill
Event Notification
The Uicontrol class provides a standard mechanism for registering and receiving events. This allows you to specify a method in which your control notifies the proxy class when a particular event occurs. If you want to register an event, you can use the Addtarget method:
[MyControl addtarget:mydelegate Action: @selector (Myactionmethod:) forcontrolevents: Uicontroleventvaluechanged];
events can be combined with logical OR, so multiple events can be specified again in a separate addtarget call. The following events are supported by the base class Uicontrol, and are applicable to all controls unless otherwise noted
Uicontrolevents Enumeration Types
uicontroleventtouchdown//Single Touch Press event: The user touches the screen, or when a new finger falls. uicontroleventtouchdownrepeat//Multi-Touch press event, touch count greater than 1: when the user presses the second to third or fourth finger. uicontroleventtouchdraginside//when a touch is dragged within the control window. uicontroleventtouchdragoutside//when a touch is dragged outside the control window. uicontroleventtouchdragenter//when a touch is dragged from outside the control window to the inside. uicontroleventtouchdragexit//when a touch is dragged from inside the control window to the outside. uicontroleventtouchupinside//all touch lift events within the control. uicontroleventtouchupoutside//all touch lift events outside the control (the touch must start with the inside of the control to send a notification). uicontroleventtouchcancel//all touch cancellation events, that is, one touch is canceled because it has too many fingers, or is locked or interrupted by a phone call. uicontroleventtouchchanged//a notification is sent when the value of the control changes. Used for sliders, segmented controls, and other controls that take values. You can configure when a slider control sends notifications when the slider is dropped, or when it is dragged. uicontroleventeditingdidbegin//a notification is sent when the text control starts editing. uicontroleventeditingchanged//sends a notification when text in a text control is changed. uicontroleventeditingdidend//a notification is sent when the edit ends in a text control. uicontroleventeditingdidonexit//sends a notification when the edit is finished by pressing the ENTER key (or equivalent behavior) within the text control. uicontroleventalleditingevents//notifies all events about text editing. Uicontroleventallevents
-(void) Removetarget: (nullable ID) Target action: (nullable SEL) Action forcontrolevents: (uicontrolevents) ControlEvents;
to delete the corresponding action for one or more events, you can use the Removetarget method of the Uicontrol class. You can delete all actions for a given event target by using the nil value:
[MyControl removetarget:mydelegate Action:nil forcontrolevents:uicontroleventallevents];
-(Nsset *) alltargets;
to get a list of all the specified actions for a control, you can use the Alltargets method. This method returns a Nsset that contains a complete list of events:
nsset* myactions = [Myconreol alltargets];
-(Nullable nsarray<nsstring *> *) Actionsfortarget: (nullable ID) target forcontrolevent: (uicontrolevents) ControlEvent;
In addition, you can use the Actionsfortarget method to get a list of all the actions for a particular event target:
nsarray* myactions = [MyControl actionfortarget:uicontroleventvaluechanged];
-(void) SendAction: (SEL) Action to: (Nullable ID) target forevent: (Nullable uievent *) event;
If you have designed a custom control class, you can use the Sendactionsforcontrolevent method to send notifications for basic Uicontrol events or your own custom events. For example, if your control's value is changing, you can
Sends a notification that the control's code can specify a time target that will be propagated to those specified targets. Cases:
[Self sendactionsforcontrolevents:uicontroleventvaluechanged];
Tracking Touch Events
If you are trying to provide custom tracking behavior, you can override the following methods:
-(BOOL) Begintrackingwithtouch: (Uitouch *) Touch withevent: (uievent *) event-(BOOL) Continuetrackingwithtouch: ( Uitouch *) Touch withevent: (uievent *) event-(void) Endtrackingwithtouch: (Uitouch *) Touch withevent: (uievent *) event-( void) Canceltrackingwithevent: (Uievent *) event
these four methods correspond to start, move, end, and cancel four states respectively. Does it look familiar? Does this look like the four event tracking methods provided by Uiresponse? Let's take a look at Uiresponse's four ways:
-(void) Touchesbegan: (Nsset *) touches withevent: (Uievent *) event-(void) touchesmoved: (Nsset *) touches withevent: ( Uievent *) event-(void) touchesended: (Nsset *) touches withevent: (Uievent *) event-(void) touchescancelled: (NSSet *) Touches withevent: (Uievent *) event
As we can see, the parameters of the above two groups of methods are basically the same, except that the Uicontrol is for a single touch, while the uiresponse may be multi-touch. In addition, the return value is similar. Since Uicontrol itself is a view, it also actually inherits these four methods of Uiresponse. If we test it, we will find that both sets of methods are called and do not interfere when touch events occur for the control.
To determine whether the current object is tracking touch operations, Uicontrol defines a tracking property. If yes, the value indicates that it is being traced. This is more convenient for us, and we don't need to define a variable to handle it.
In the test, we can find that when our touch points move out of the control area name along the screen, we continue to trace the touch operation, Canceltrackingwithevent: The message was not sent. To determine whether the current touch point is in the control area class, you can use the Touchinside property, which is a read-only property. However, the result of the measurement is that within a certain range around the control area, the value is still marked as yes, meaning that the area used to determine touchinside is greater than the control area.
observe or modify the behavior message that is distributed to the target objectfor a given event, Uicontrol calls SendAction:to:forEvent: To forward the behavior message to the UIApplication object, which is then called by the UIApplication object sendaction:to: Fromsender:forevent: method to distribute the message to the specified target, and if we do not specify a target, the event is distributed to the first object on the response chain that wants to process the message. You can override this method if the subclass wants to monitor or modify this behavior.
In our example, we did a little processing to put the externally added target-action inside the control to handle the event, so our code is implemented as follows:
lxcontrol.h-(void) SendAction: (SEL) action to: (ID) Target forevent: (Uievent *) event { //events are passed to the object itself to handle [ Super SendAction: @selector (handleaction:) to:self forevent:event];} -(void) Handleaction: (ID) Sender { NSLog (@ "Handle Action");} viewcontroller.m-(void) viewdidload { [super viewdidload]; Self.view.backgroundColor = [Uicolor whitecolor]; LxControl.h *control = [[LxControl.h alloc] Initwithframe:cgrectmake (+, +, +)]; [Control addtarget:self Action: @selector (Tapimagecontrol:) forcontrolevents:uicontroleventtouchupinside]; [Self.view Addsubview:control]} -(void) Tapimagecontrol: (ID) Sender { NSLog (@ "sender =%@", sender);}
Printing results:
Since we rewrote the SendAction:to:forEvent: method, the last selector to handle the event is ImageControl handleaction: Method, Rather than Viewcontroller's Tapimagecontrol: method.
In addition, SendAction:to:forEvent: is actually also called by another method of Uicontrol, that is, sendactionsforcontrolevents:. The function of this method is to send all the behavior messages related to the specified type. We can call this method of the control anywhere (both inside and outside the control) to send the parameter controlevents the specified message. In our example, the following tests were made in VIEWCONTROLLER.M:
-(void) viewdidload { [Control addtarget:self Action: @selector (Tapimagecontrol:) forControlEvents: UIControlEventTouchUpInside]; [Control sendactionsforcontrolevents:uicontroleventtouchupinside];}
you can see that the UIControlEventTouchUpInside event is triggered when the control is not clicked, and the handle action log is printed.
Management of Target-actionIn fact, we can look at the internal structure of the Uicontrol by breaking a breakpoint at a suitable location in the program, and see the result:
Therefore, Uicontrol internally actually has a mutable array (_targetactions) to hold the target-action, and each element in the array is a Uicontroltargetaction object. The Uicontroltargetaction class is a private class, and we can find its header file in Ios-runtime-header:
@interface uicontroltargetaction:nsobject { SEL _action; BOOL _cancelled; unsigned int _eventmask; ID _target;} @property (nonatomic) BOOL cancelled;-(void). cxx_destruct;-(bool) cancelled;-(void) setcancelled: (bool) arg1; @end
You can see that the Uicontroltargetaction object maintains the three essential elements that a target-action must have, namely target,action and the corresponding event eventmask.
If you think about it, you'll find an interesting question. Let's take a look at the reference relationship between Viewcontroller (target) and ImageControl instance (control) in the instance, as shown in:
Well, circular references.
In this case, we must find ways to break this circular reference. So what is the best place to do it in these 5 links? Careful thinking, 1, 2, 4 is certainly not, 3 is not very suitable, it is only 5. In the above uicontroltargetaction header file, there is no way to see _target is declared in weak way, there is evidence?
We make a symbolic breakpoint in the project, as shown below:
Running the program, the program goes into the assembly code page of the [Uicontrol addTarget:action:forControlEvents:] method, where we can find some clues. As shown in the following:
As you can see, for the _target member variable, the objc_storeweak is called in the Uicontroltargetaction initialization method, that is, this member variable refers to the target object that is passed in by the outside in weak way.
In fact, in the Uicontrol document, AddTarget:action:forControlEvents: The description of the method also has this sentence:
When you call the This method, the target is not retained.
Also, if we call addTarget:action:forControlEvents multiple times with the same set of Target-action and event: method, in _ Uicontroltargetaction objects are not added repeatedly in targetactions.
Reference: Demo (Svsegmentedcontrol) Https://github.com/samvermette/SVSegmentedControl
Uicontrol of UI controls