carekit-apple / CareKit

CareKit is an open source software framework for creating apps that help people better understand and manage their health.
https://www.researchandcare.org
Other
2.41k stars 443 forks source link

Use of slider in Carekit care view #320

Open scdi opened 5 years ago

scdi commented 5 years ago

Would it be possible to create a slider view as in the pasted picture? We could something similar to an OCKButtonLogTaskViewController but instead of the instructions that appear above the cell with the button, we could have a slider to log something like pain level. image. This is not an issue but feature request. I am not sure where else to ask for a feature request.

erik-apple commented 5 years ago

@scdi Thanks for opening an issue! It's helpful for us to know which features the community is interested in! I'll file this issue as a feature proposal. It's been brought up once previously in #274.

If enough people show interest, we may consider adding it into CareKit.

This would also be a great place for contributors to pitch in! We've laid the groundwork so that it's easy to write new views -- basically you just need to create a subclass of UIView that conforms to OCKEventDisplayable.

jwaddilove commented 5 years ago

+1 on this feature request. Agree medication events are binary but many assessments are score related. Pain is the obvious on but mobility, vision, shaking and ashtma could also have variable scores.

ericlewis commented 4 years ago

As per the comment in #274 you technically have everything you need to implement a view like this, I will post some example code soon.

xiangyu-sun commented 4 years ago

Seems like the path has been narrowed down to subclass OCKButtonLogTaskView and the other two collection view datasource if we want to a customized logging UI.

But my problem will stay the same as long as I don't override the function open func taskView(_ taskView: UIView & OCKTaskDisplayable, didCreateOutcomeValueAt index: Int, eventIndexPath: IndexPath, sender: Any?) inside OCKTaskViewController. Calling delegate?.taskView(self, didCreateOutcomeValueAt:, eventIndexPath: from OCKButtonLogTaskView is not enough to create an event with non-binary Outcome.

Is there a documented way I can add an outcome with integer value type easily without think about subclassing OCKTaskViewController? Maybe just like how OCKGridTaskViewController is done?

gavirawson-apple commented 4 years ago

It sounds like you're on the right track. Here is the code that gets a slider log set up:


// 1. Create a view with a slider above the log button.

class SliderLogTaskView: OCKButtonLogTaskView {

    let slider: UISlider = {
        let slider = UISlider()
        slider.maximumValue = 0
        slider.maximumValue = 10
        return slider
    }()

    override init() {
        super.init()
        contentStackView.insertArrangedSubview(slider, at: 1)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// 2. Create a custom view synchronizer for the `SliderLogTaskView`.

class SliderLogTaskViewSynchronizer: OCKButtonLogTaskViewSynchronizer {

    override func makeView() -> OCKButtonLogTaskView {
        SliderLogTaskView()
    }

    override func updateView(_ view: OCKButtonLogTaskView, context: OCKSynchronizationContext<OCKTaskEvents?>) {
        super.updateView(view, context: context)

        let event = context.viewModel?.firstEvent
        let values = event?.outcome?.values.map { $0 }

        // You can display the `values` as you wish here.
    }
}

// 3. Create a view controller that ties everything together.

class SliderLogTaskViewController: OCKButtonLogTaskViewController {

    override func taskView(_ taskView: UIView & OCKTaskDisplayable,
                           didCreateOutcomeValueAt index: Int,
                           eventIndexPath: IndexPath, sender: Any?) {

        // Grab the value from the slider and save it as an outcome value
        let view = taskView as! SliderLogTaskView
        let value = Int(view.slider.value)
        controller.appendOutcomeValue(withType: value, at: eventIndexPath, completion: nil)
    }
}

// 4. Instantiate the view controller when needed

let viewController= SliderLogTaskViewController(
    viewSynchronizer: SliderLogTaskViewSynchronizer(),
    taskID: taskID,
    eventQuery: eventQuery,
    storeManager: storeManager)