RxDataSources icon indicating copy to clipboard operation
RxDataSources copied to clipboard

About customizing row height for RxPickerViewViewAdapter.

Open HowsonLiu opened this issue 2 years ago • 0 comments

lazy var pickerAdapter: RxPickerViewViewAdapter<Array<Any>> = {
        return RxPickerViewViewAdapter<Array<Any>>(components: [],
                                                   numberOfComponents: { _,_,_ in 1 },
                                                   numberOfRowsInComponent: { _,_,items,_ in items.count},
                                                   viewForRow: { [weak self] _,_,items,row,_,_ -> UIView in
            let label = Label(text: "\(items[row])")
            label.font = self?.pickerFont
            if self?.pickerAxis == .horizontal {
                label.transform = CGAffineTransform(rotationAngle: .pi / 2)
            }
            return label
        })
    }()

Observable.just(pickerItems)
                .bind(to: pickerView.rx.items(adapter: pickerAdapter))
                .disposed(by: pickerDisposeBag)

I would like to set the height of the label to 100. I see that RxPickerViewViewAdapter inherits from UIPickerViewDelegate.However, there is no handling of rowHeightForComponent in RxPickerViewViewAdapter. I tried adding an extension to RxPickerViewViewAdapter

extension RxPickerViewViewAdapter {
   public func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return 100
    }
}

or subclassing it and overriding the rowHeightForComponent method.

open class RxPickerViewHeightViewAdapter<Components>: RxPickerViewViewAdapter<Components> {
    
    public typealias HeightOfRowsInComponent = (
        _ dataSource: RxPickerViewHeightViewAdapter<Components>,
        _ pickerView: UIPickerView,
        _ components: Components,
        _ component: Int
    ) -> CGFloat
    
    private let heightOfRowsInComponent: HeightOfRowsInComponent
    
    fileprivate var components: Components
    
    public init(components: Components,
                numberOfComponents: @escaping NumberOfComponents,
                numberOfRowsInComponent: @escaping NumberOfRowsInComponent,
                viewForRow: @escaping ViewForRow,
                heightOfRowsInComponent: @escaping HeightOfRowsInComponent) {
        self.components = components
        self.heightOfRowsInComponent = heightOfRowsInComponent
        super.init(components: components,
                   numberOfComponents: numberOfComponents,
                   numberOfRowsInComponent: numberOfRowsInComponent,
                   viewForRow: viewForRow)
    }
    
    open func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return self.heightOfRowsInComponent(self, pickerView, components, component)
    }   
}

but they both didn't work In the end, I modified the source code of RxPickerViewViewAdapter

open class RxPickerViewViewAdapter<Components>: RxPickerViewDataSource<Components>, UIPickerViewDelegate {
    /**
     - parameter dataSource
     - parameter pickerView
     - parameter components
     - parameter row
     - parameter component
     - parameter view
    */
    public typealias ViewForRow = (
        _ dataSource: RxPickerViewViewAdapter<Components>,
        _ pickerView: UIPickerView,
        _ components: Components,
        _ row: Int,
        _ component: Int,
        _ view: UIView?
    ) -> UIView
    
    private let viewForRow: ViewForRow
    
    /**
     - parameter dataSource
     - parameter pickerView
     - parameter components
     - parameter component
    */
    public typealias RowHeightForComponent = (
        _ dataSource: RxPickerViewViewAdapter<Components>,
        _ pickerView: UIPickerView,
        _ components: Components,
        _ component: Int
    ) -> CGFloat
    
    private let rowHeightForComponent: RowHeightForComponent

    /**
     - parameter components: Initial content value.
     - parameter numberOfComponents: Implementation of corresponding delegate method.
     - parameter numberOfRowsInComponent: Implementation of corresponding delegate method.
     - parameter viewForRow: Implementation of corresponding adapter method that converts component to `UIView`.
     */
    public init(components: Components,
                numberOfComponents: @escaping NumberOfComponents,
                numberOfRowsInComponent: @escaping NumberOfRowsInComponent,
                rowHeightForComponent: @escaping RowHeightForComponent,
                viewForRow: @escaping ViewForRow) {
        self.viewForRow = viewForRow
        self.rowHeightForComponent = rowHeightForComponent
        super.init(components: components,
                   numberOfComponents: numberOfComponents,
                   numberOfRowsInComponent: numberOfRowsInComponent)
    }
    
    open func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        return viewForRow(self, pickerView, components, row, component, view)
    }
    
    open func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return rowHeightForComponent(self, pickerView, components, component)
    }
}

and it worked so are there any better solutions about this question? should i submit a mr?

HowsonLiu avatar Mar 11 '23 08:03 HowsonLiu