EurekaCommunity / ViewRow

ViewRow is a Eureka row that allows you to display any UIView (or UIView sunclass) within a Eureka row. Views can be created in code or loaded from nib files.
MIT License
77 stars 16 forks source link

Accessing value of textField inside View displayed via ViewRow #16

Closed SigmundRakes closed 6 years ago

SigmundRakes commented 6 years ago

Good day,

I haven't found a doc/workaround on how to access row.value using ViewRow.

I have a textfield called customTextField inside of a View that i'm calling into ViewRow via cell.View = customView

Any help will be appreciated! Thanks

     <<< ViewRow { (row) in
              row.title = "Description"
              row.tag = "dooly"
           }

             .cellSetup { (cell, row) in
              //Construct the view for the cell
              cell.view = self.customView
            }
var customView: UIView = {
        let view = UIView()
        view.backgroundColor = .red
        view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 64)

        let customLabel = UILabel()
        customLabel.text = "Description"

        let customTextField = UITextField()
        customTextField.placeholder = "enter text here"

        view.addSubview(customLabel)
        customLabel.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: nil, paddingTop: 5, paddingLeft: 20, paddingBottom: 0, paddingRight: 0, width: 22, height: 8)

        view.addSubview(customTextField)
        customTextField.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: nil, paddingTop: 10, paddingLeft: 20, paddingBottom: 0, paddingRight: 0, width: view.frame.width, height: 40)

        return view
    }()
alldritt commented 6 years ago

I can imagine two approaches to the problem:

  1. Us tags. Assign a tag (integer value) to each of the views you are creating. Then, you can use UIView's viewWithTag function to find the view again:
let customTextFieldTag = 123

var customView: UIView = {
        let view = UIView()
        view.backgroundColor = .red
        view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 64)

        let customLabel = UILabel()
        customLabel.text = "Description"

        let customTextField = UITextField()
        customTextField.placeholder = "enter text here"
        customTextField.tag = customTextFieldTag

        view.addSubview(customLabel)
        customLabel.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: nil, paddingTop: 5, paddingLeft: 20, paddingBottom: 0, paddingRight: 0, width: 22, height: 8)

        view.addSubview(customTextField)
        customTextField.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: nil, paddingTop: 10, paddingLeft: 20, paddingBottom: 0, paddingRight: 0, width: view.frame.width, height: 40)

        return view
    }()

then you can re-aquire the text field like this:

let customTextField = self.customView.viewWithTag(customTextFieldTag) as! UITetField
  1. Us a UIView subclass to retain a public property for the custom text field:
class MyUIView : UIView {
    var customTextField: UITextField!
}

var customView: MyUIView = {
        let view = MyUIView()
        view.backgroundColor = .red
        view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 64)

        let customLabel = UILabel()
        customLabel.text = "Description"

        view.customTextField = UITextField()
        view.customTextField.placeholder = "enter text here"

        view.addSubview(customLabel)
        customLabel.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: nil, paddingTop: 5, paddingLeft: 20, paddingBottom: 0, paddingRight: 0, width: 22, height: 8)

        view.addSubview(customTextField)
        customTextField.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: nil, paddingTop: 10, paddingLeft: 20, paddingBottom: 0, paddingRight: 0, width: view.frame.width, height: 40)

        return view
    }()

then, to reference the text field:

self.customView.customeTextField

I hope this helps...

SigmundRakes commented 6 years ago

Thanks!! Will have a go later today

saurabhPV commented 5 years ago

But none of these options can assign value to row from the view itself. This is important because then I can retrieve it using form.values() . But even more important issue is, the type of value is string is there a way we can change the type of it ?

alldritt commented 5 years ago

If you want to have a link back to the row from the view, you'll have to implement that yourself in your UIView subclass, and then initialize the view's reference to the row when you are constructing the row. I suggest a weak reference to the row to ensure that the row deallocates properly.

saurabhPV commented 5 years ago

That was super quick! Thanks!! I figured that out but don't know how to change the data type of the row value.

alldritt commented 5 years ago

As you've found, the row's value type is defined as String. The ViewRow code never uses the value property and I didn't anticipate someone wanting to retain a value within the row its self. In all my uses of ViewRow, I've found it simpler to retain any value within the row's view, hence the view property I provide:

(form.rowBy(tag: "myTag") as? ViewRow<UIImageView>)?.view.image = UIImage(named: "Testing")

I acknowledge that saying something like the following offers better encapsulation:

(form.rowBy(tag: "myTag") as? ViewRow<UIImageView, UIImage>)?.value = UIImage(named: "Testing")

At this stage, introducing a new generic parameter to the ViewRow class in order to specify the row's value type represents a breaking change for all those already using ViewRow. For this reason, I'm reluctant to make this change.

Then there is the question of what happens when the row's value is changed? Should this have any impact on the view? If so, the view would have to adopt some sort of protocol defining an API for notifying the view of a row's value change.

alldritt commented 5 years ago

I've created a branch (ValueTypeSpecialization) that introduces a new ViewRow class called ViewRowNew (I know, I need a better name) that allows the row's value type to be specified:

let myRow = ViewRowNew<MyView, Int>("myTag")...
saurabhPV commented 5 years ago

I acknowledge that saying something like the following offers better encapsulation: (form.rowBy(tag: "myTag") as? ViewRow<UIImageView, UIImage>)?.value = UIImage(named: "Testing

Yes that's exactly my point is.

I've created a branch (ValueTypeSpecialization) that introduces a new ViewRow class called ViewRowNew (I know, I need a better name) that allows the row's value type to be specified:

Now that's neat! I will try this and let you know. Thanks a lot for taking out the time to implement this.

And I will suggest instead of creating a new class is it possible to have the same class with default value type as string. I am new to swift so I don't know if the default param as value type works or not but may be that would not break existing code. (Plus , you don't need to worry about coming up with new name for it ;-) )

alldritt commented 5 years ago

And I will suggest instead of creating a new class is it possible to have the same class with default value type as string.

It turns out that Swift (as of 4.2) does not allow default values for generic specializations. Were that possible, then yes, it would be simple to extend ViewRow.