View - Tai-Kimura/SwiftJsonUI GitHub Wiki

View

class: SJUIView inherits: UIView child classes: [GradientView](/Tai-Kimura/SwiftJsonUI/wiki/GradientView), [SJUISelectBox](/Tai-Kimura/SwiftJsonUI/wiki/SelectBox)

Platform Support

  • UIKit: Full support (All attributes available)
  • SwiftUI: Full support (All attributes available through DynamicComponent)
    • SafeAreaView maps to SwiftUI's native safe area handling
  • Jetpack Compose: Full support (Maps to Box/Column/Row based on orientation)
  • Android XML: Maps to LinearLayout (with orientation) or ConstraintLayout (without orientation)
    • View with orientation: "horizontal"LinearLayout (horizontal)
    • View with orientation: "vertical"LinearLayout (vertical)
    • View without orientation → ConstraintLayout
    • SafeAreaView → com.kotlinjsonui.views.KjuiSafeAreaView

Attributes for View

attribute name UIKit SwiftUI Compose XML type in json details remarks
orientation string View orientation: vertical, horizontal. Behaves like Linear Layout XML: android:orientation
direction string Layout direction: topToBottom, bottomToTop, leftToRight, rightToLeft
gravity string Content gravity: top, bottom, centerVertical, left, right, centerHorizontal XML: android:gravity
highlightBackground string Background color when highlighted Dynamic mode only
highlighted boolean View highlighted state Dynamic mode only
canTap boolean Enable tap capability. Prevents background color change when false XML: android:clickable
tapBackground string Background color when tapped XML: selector drawable
onclick string Tap gesture selector XML: android:onClick
onClick string Closure-based tap handler ((UITapGestureRecognizer) -> Void) XML: android:onClick
onLongPress string Long press closure handler
onPan string Pan gesture closure handler
onPinch string Pinch gesture closure handler
events dictionary Complex event handlers with multiple gesture types Dynamic mode only
touchDisabledState string Touch handling control: none, onlyMe, viewsWithoutTouchEnabled, viewsWithoutInList Dynamic mode only
touchEnabledViewIds array List of view IDs that remain touch-enabled Dynamic mode only
safeAreaInsetPositions array SafeAreaView edges: ["all"], ["top", "bottom"], etc. SafeAreaView only; XML: KjuiSafeAreaView
shadow JSON Shadow configuration with color, offset, radius, opacity XML: android:elevation
clipToBounds boolean Clip content to bounds XML: android:clipChildren
userInteractionEnabled boolean Enable user interaction XML: android:enabled
semanticContentAttribute string RTL/LTR layout direction UIKit only

Properties for View

open class var viewClass: SJUIView.Type

this property will be used to decide which class to inflate with createFromJSON method. You should define the view's class on this property when you create classes inherite SJUIView.

open class var canTap: Bool

Explanation is in Attributes table.

open class var highlighted: Bool

Explanation is in Attributes table.

open class var orientation: SJUIView.Orientation

Explanation is in Attributes table. You should call resetConstraintInfo method to apply view's constraint after changing this property.

open class var direction: SJUIView.Direction

Explanation is in Attributes table. You should call resetConstraintInfo method to apply view's constraint after changing this property.

open class var gravity: SJUIView.Gravity

Explanation is in Attributes table. You should call resetConstraintInfo method to apply view's constraint after changing this property.

Functions for View

open override func didAddSubview(_ subview: UIView)

inherited from UIView. this method will call when subview is added. resetConstraintInfo will call when this method is called.

public func addSubViewWith(json: JSON, target: Any, withCreatorClass creator: SJUIViewCreator.Type = SJUIViewCreator.self)

Use this method when you want to add subview created from json file from code.

public class func createFromJSON(attr: JSON, target: Any, views: inout [String: UIView]) -> SJUIView

This method will be called when it's created from json file. Override This method when you create classes inherite SJUIView class.

TouchDisabledState Implementation Examples

Example 1: Basic touchDisabledState Usage

{
  "type": "View",
  "id": "container",
  "width": "matchParent",
  "height": "matchParent",
  "touchDisabledState": "onlyMe",
  "background": "#CCCCCC",
  "child": [
    {
      "type": "Button",
      "id": "button1",
      "width": 100,
      "height": 50,
      "text": "Clickable",
      "onclick": "buttonTapped"
    }
  ]
}

In this example, the container view cannot be tapped, but the button inside remains clickable.

Example 2: Using touchEnabledViewIds

{
  "type": "View",
  "id": "parentView",
  "width": "matchParent",
  "height": "matchParent",
  "touchDisabledState": "viewsWithoutInList",
  "touchEnabledViewIds": ["allowedButton", "allowedLabel"],
  "background": "#EEEEEE",
  "child": [
    {
      "type": "Button",
      "id": "allowedButton",
      "width": 120,
      "height": 50,
      "text": "Allowed",
      "onclick": "allowedButtonTapped"
    },
    {
      "type": "Button",
      "id": "blockedButton",
      "width": 120,
      "height": 50,
      "text": "Blocked",
      "onclick": "blockedButtonTapped"
    },
    {
      "type": "Label",
      "id": "allowedLabel",
      "width": "wrapContent",
      "height": "wrapContent",
      "text": "Clickable Label",
      "onclick": "labelTapped"
    }
  ]
}

Only "allowedButton" and "allowedLabel" will receive touch events. "blockedButton" will not respond to touches.

Example 3: Conditional Touch Enabling with Data Binding

{
  "type": "View",
  "id": "conditionalView",
  "width": "matchParent",
  "height": 200,
  "data": [
    {
      "name": "isInteractionEnabled",
      "class": "Bool",
      "defaultValue": true
    },
    {
      "name": "enabledViewIds",
      "class": "[String]",
      "defaultValue": []
    }
  ],
  "touchDisabledState": "@{isInteractionEnabled ? 'none' : 'viewsWithoutInList'}",
  "touchEnabledViewIds": "@{enabledViewIds}",
  "background": "#F0F0F0",
  "child": [
    {
      "type": "Button",
      "id": "controlButton",
      "width": 150,
      "height": 50,
      "text": "Toggle Interaction",
      "onclick": "toggleInteraction"
    },
    {
      "type": "Button",
      "id": "actionButton",
      "width": 120,
      "height": 50,
      "text": "Action",
      "onclick": "performAction"
    }
  ]
}

This example shows how to dynamically control touch behavior using data binding.

Swift Implementation Example

class ViewController: UIViewController {
    @IBOutlet weak var containerView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTouchControlledView()
    }
    
    func setupTouchControlledView() {
        let jsonString = """
        {
            "type": "View",
            "id": "touchControlledContainer",
            "width": "matchParent",
            "height": 300,
            "touchDisabledState": "viewsWithoutInList",
            "touchEnabledViewIds": ["enabledButton"],
            "background": "#E8E8E8",
            "child": [
                {
                    "type": "Button",
                    "id": "enabledButton",
                    "width": 140,
                    "height": 50,
                    "text": "Enabled",
                    "onclick": "enabledButtonTapped"
                },
                {
                    "type": "Button",
                    "id": "disabledButton", 
                    "width": 140,
                    "height": 50,
                    "text": "Disabled",
                    "onclick": "disabledButtonTapped"
                }
            ]
        }
        """
        
        if let jsonData = jsonString.data(using: .utf8),
           let json = try? JSON(data: jsonData) {
            let createdView = SJUIViewCreator.viewFromJSON(json, target: self)
            containerView.addSubview(createdView)
            createdView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                createdView.topAnchor.constraint(equalTo: containerView.topAnchor),
                createdView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
                createdView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
                createdView.heightAnchor.constraint(equalToConstant: 300)
            ])
        }
    }
    
    @objc func enabledButtonTapped() {
        print("Enabled button was tapped")
    }
    
    @objc func disabledButtonTapped() {
        print("This will not be called due to touchDisabledState")
    }
}

Dynamic touchDisabledState Control

Currently, touchDisabledState can be controlled dynamically using data binding syntax @{}, but there is no specific handler implementation in binding_builder for this attribute. If you need to change touchDisabledState dynamically from Swift code, you would need to:

  1. Access the view directly and modify the property:
if let containerView = view.findViewWithId("container") as? SJUIView {
    containerView.touchDisabledState = .viewsWithoutInList
    containerView.touchEnabledViewIds = ["newAllowedButton"]
}
  1. Use invalidate methods to refresh the layout after changes:
// After modifying touchDisabledState or touchEnabledViewIds
containerView.setNeedsLayout()
containerView.layoutIfNeeded()
  1. Consider adding custom handler support:
# This could be added to view_binding_handler.rb in the future:
when "touchDisabledState"
  @binding_content << "        #{view_name}?.touchDisabledState = TouchDisabledState(rawValue: #{value}) ?? .none\n"
  true
when "touchEnabledViewIds"
  @binding_content << "        #{view_name}?.touchEnabledViewIds = #{value}\n"
  true

Note: For full dynamic control through binding_builder, custom handler implementation would be needed in the view_binding_handler.rb file.