How could I set the width of UIPickerView - swift

my interface screenshot
I tried to set the width of a UIPickerView, but it didn't work.
For example, i used
class Coordinator : NSObject,UIPickerViewDelegate,UIPickerViewDataSource{
...
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let view = UIView(frame: CGRect(x:0,y:0,width:128,height:60))
...
return view
}
...
}
above code,could only change the width of the red block.
i want to change the width of the whole picker,including the half-opacity-block.
struct CustomPicker : UIViewRepresentable{
...
func makeUIView(context: UIViewRepresentableContext<CustomPicker>) -> UIPickerView {
let picker = UIPickerView(frame: CGRect(x: 0, y: 0, width: 50, height: 60))
return picker
}
}
above code didn't work .
In addition , is there some func could hide/remove/custom the half-opacity-mask ?
waiting for you help ! thx a lot :) !
Here's whole codes.
// ContentView
import SwiftUI
struct ContentView: View {
#State var selectedWeight : dataListItemModel = dataListItemModel(label: "1KG", value: 1)
#State var selectedTimes : dataListItemModel = dataListItemModel(label: "1RM", value: 1)
let timesDataList : [dataListItemModel] = [
dataListItemModel(label: "1RM", value: 1),
dataListItemModel(label: "2RM", value: 2),
dataListItemModel(label: "3RM", value: 3),
]
let weightDataList : [dataListItemModel] = [
dataListItemModel(label: "1.25KG", value: 1.25),
dataListItemModel(label: "2.5KG", value: 2.5),
dataListItemModel(label: "5KG", value: 5),
]
var body: some View {
HStack{
CustomPicker(selected: self.$selectedWeight,dataList: weightDataList,width: 200)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
// CustomPicker
import SwiftUI
import UIKit
struct dataListItemModel : Identifiable {
let id : String = UUID().uuidString
let label : String
let value : Double
init(label : String, value : Double) {
self.label = label
self.value = value
}
}
struct CustomPicker : UIViewRepresentable{
#Binding var selected : dataListItemModel
let dataList : [dataListItemModel]
let width : CGFloat
func makeCoordinator() -> CustomPicker.Coordinator {
return CustomPicker.Coordinator(parent1: self)
}
func makeUIView(context: UIViewRepresentableContext<CustomPicker>) -> UIPickerView {
let picker = UIPickerView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width/3, height: 60))
picker.dataSource = context.coordinator
picker.delegate = context.coordinator
// picker.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return picker
}
func updateUIView(_ uiView: UIPickerView, context: UIViewRepresentableContext<CustomPicker>) {
}
class Coordinator : NSObject,UIPickerViewDelegate,UIPickerViewDataSource{
var parent : CustomPicker
let dataList : [dataListItemModel]
let width : CGFloat
init(parent1 : CustomPicker) {
parent = parent1
dataList = parent1.dataList
width = parent1.width
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return dataList.count
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
// pickerView.subviews.forEach({
// // $0.frame = CGRect(x:0,y:0,width:width,height:60)
//1
// $0.isHidden = $0.frame.height < 1.0
// })
return 1
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let view = UIView(frame: CGRect(x:0,y:0,width:width,height:60))
let label = UILabel(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height))
label.text = dataList[row].label
label.textColor = .white
label.textAlignment = .center
label.font = .systemFont(ofSize: 22,weight:.bold)
label.adjustsFontSizeToFitWidth = true
label.numberOfLines = 1
view.backgroundColor = .red
view.addSubview(label)
view.clipsToBounds = true
view.layer.cornerRadius = 8
return view
}
func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
return width
}
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 60
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.parent.selected = dataList[row]
}
}
}
class Host : UIHostingController<ContentView>{
override var preferredStatusBarStyle: UIStatusBarStyle{
return .lightContent
}
}

Related

UIPickerView as input for TextField() in SwiftUI

I am trying to display a picker view as keyboardinputtype for TextField() in SwiftUI. I want to display a list of nationalities which the user can then select.
SwiftUI's TextField does not have inputView property like as UITextField.
But You can use UITextfield and UIPickerView using UIViewRepresentable
First make TextFieldWithInputView.swift file and add below code in it
struct TextFieldWithInputView : UIViewRepresentable {
var data : [String]
var placeholder : String
#Binding var selectionIndex : Int
#Binding var selectedText : String?
private let textField = UITextField()
private let picker = UIPickerView()
func makeCoordinator() -> TextFieldWithInputView.Coordinator {
Coordinator(textfield: self)
}
func makeUIView(context: UIViewRepresentableContext<TextFieldWithInputView>) -> UITextField {
picker.delegate = context.coordinator
picker.dataSource = context.coordinator
picker.backgroundColor = .gray
picker.tintColor = .black
textField.placeholder = placeholder
textField.inputView = picker
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<TextFieldWithInputView>) {
uiView.text = selectedText
}
class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate , UITextFieldDelegate {
private let parent : TextFieldWithInputView
init(textfield : TextFieldWithInputView) {
self.parent = textfield
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return self.parent.data.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return self.parent.data[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.parent.$selectionIndex.wrappedValue = row
self.parent.selectedText = self.parent.data[self.parent.selectionIndex]
self.parent.textField.endEditing(true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.parent.textField.resignFirstResponder()
}
}
}
Then, You can use it in your contentView like as below
struct ContentView : View {
#State var country : String? = nil
#State var arrCountry = ["India","USA","France"] //Here Add Your data
#State var selectionIndex = 0
var body : some View {
VStack {
TextFieldWithInputView(data: self.arrCountry, placeholder: "Select your country", selectionIndex: self.$selectionIndex, selectedText: self.$country)
.frame(width: 300, height: 50)
.border(Color.black)
}
}
}
Here is output

Where am I going wrong adding images to my UIPickerView?

Mine is an educational app, the student is given a word and then is supposed to select the corresponding image (say matching the word banana to the image of one, where the image is in a UIPickerview) However, my following code yields no results:
let possibleAnswers = [UIImage(named: Images.one), UIImage(named: Images.two), UIImage(named: Images.three), UIImage(named: Images.four)]
fileprivate let pickerView: UIPickerView = {
let pv = UIPickerView()
pv.translatesAutoresizingMaskIntoConstraints = false
return pv
}()
override func viewDidLoad() {
pickerView.delegate = self
pickerView.dataSource = self
}
extension ViewController: UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return possibleAnswers.count
}
}
extension ViewController: UIPickerViewDelegate {
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let myImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 220, height: 61))
myImageView.image = possibleAnswers[row]
return myImageView
}
}
Am I doing something wrong? How can I rectify this?
EDIT 1:
This is what the erroneous view looks like.
Set PickerView row Height to match your image size using rowHeightForComponent function
class ViewController: UIViewController,UITextFieldDelegate{
fileprivate let possibleAnswers:[UIImage] = [UIImage(named: "apple.png")!,UIImage(named: "banana.png")!,UIImage(named: "orange.png")!]
fileprivate var pickerView: UIPickerView?
fileprivate var toolBar:UIToolbar?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
view.addSubview(btn)
btn.translatesAutoresizingMaskIntoConstraints = false
btn.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
btn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
btn.addTarget(self, action: #selector(test), for: .touchUpInside)
}
//MARK: Components
let btn :UIButton = {
let btn = UIButton(type: .system)
btn.setTitle("Select Correct Answer", for: .normal)
return btn
}()
}
// MARK: Pickerview Delegate
extension ViewController: UIPickerViewDelegate,UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return possibleAnswers.count
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let myImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
myImageView.image = possibleAnswers[row]
return myImageView
}
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
return 100
}
}
//MARK: Functions
extension ViewController{
#objc func test(){
pickerView = UIPickerView.init()
pickerView!.delegate = self
pickerView!.backgroundColor = UIColor.white
pickerView!.setValue(UIColor.black, forKey: "textColor")
pickerView!.autoresizingMask = .flexibleWidth
pickerView!.contentMode = .center
pickerView!.frame = CGRect.init(x: 0.0, y: UIScreen.main.bounds.size.height - 300, width: UIScreen.main.bounds.size.width, height: 300)
self.view.addSubview(pickerView!)
toolBar = UIToolbar.init(frame: CGRect.init(x: 0.0, y: UIScreen.main.bounds.size.height - 300, width: UIScreen.main.bounds.size.width, height: 50))
toolBar!.barStyle = .blackTranslucent
toolBar!.items = [UIBarButtonItem.init(title: "Done", style: .done, target: self, action: nil)]
self.view.addSubview(toolBar!)
}
}

Two UIPickerViews in one ViewController

Two PickerViews selectTypeOfWorkChoices & selectLocationChoices do not appear correctly.
A function dismissPickerView() seems working well. However, another function "createPickerView()" has some problems. Although UIpickerviews appear, I cannot see the choices in UIPickerViews and I don't know why.
Could anyone help me figure out what's wrong with my code, please??
#IBOutlet weak var selectTypeOfWorkChoices: UIPickerView!
#IBOutlet weak var selectLocationChoices: UIPickerView!
override func viewDidLoad() {
super.viewDidLoad()
createPickerView()
dismissPickerView()
}
var typeOfWork = ["--", "a", "b", "c"]
var location = ["--", "A", "B", "C"]
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
var countrows : Int = typeOfWork.count
if pickerView == selectLocationChoices {
countrows = self.location.count
}
return countrows
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView == selectTypeOfWorkChoices {
let titleRow = typeOfWork[row]
return titleRow
}
else if pickerView == selectLocationChoices {
let titleRow = location[row]
return titleRow
}
return ""
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == selectTypeOfWorkChoices {
selectedPriority = typeOfWork[row]
selectTypeOfWork.text = selectedPriority
self.selectTypeOfWork.text = self.typeOfWork[row]
}
else if pickerView == selectLocationChoices {
locationSelectedPriority = location[row]
selectLocation.text = locationSelectedPriority
self.selectLocation.text = self.location[row]
}
}
var selectedPriority : String?
var locationSelectedPriority : String?
func createPickerView() {
let pickerView = UIPickerView()
pickerView.delegate = self
self.selectTypeOfWorkChoices.delegate = self
self.selectTypeOfWorkChoices.dataSource = self
self.selectLocationChoices.delegate = self
self.selectLocationChoices.dataSource = self
selectTypeOfWork.inputView = selectTypeOfWorkChoices
selectLocation.inputView = selectLocationChoices
}
#objc func dismissPickerView() {
let toolBar = UIToolbar()
toolBar.sizeToFit()
let doneButton = UIBarButtonItem(title:"Done", style: .plain, target: self, action: #selector(self.dismissKeyboard))
toolBar.setItems([doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
selectTypeOfWork.inputAccessoryView = toolBar
selectLocation.inputAccessoryView = toolBar
}
#objc func dismissKeyboard () {
view.endEditing(true)
}
Reload the picker view after assigning an input view to your text field.
func createPickerView() {
let pickerView = UIPickerView()
pickerView.delegate = self
self.selectTypeOfWorkChoices.delegate = self
self.selectTypeOfWorkChoices.dataSource = self
self.selectLocationChoices.delegate = self
self.selectLocationChoices.dataSource = self
selectTypeOfWork.inputView = selectTypeOfWorkChoices
selectLocation.inputView = selectLocationChoices
//Reload Pickerview
self.selectTypeOfWorkChoices.reloadAllComponents()
self.selectLocationChoices.reloadAllComponents()
}

Using Extension To Access CollectionView In Separate Class

I have a class called PickerFilterClass that access the YNDropDownView library and in there I create a pickerview in PickerFilterClass's extension. I want to the pickerview help sort a collectionview in another class called RestaurantDetails. I am trying to use the pickerview didselect function to access the collectionview called productCollection and reload the data when a user pickerview selects an row. I here is how I am trying to do this:
PickerFilter Class
class PickerFilterClass: YNDropDownView {
#IBOutlet var pickerView: UIPickerView!
var rotationAngle: CGFloat!
var filteredProducts = [Product]()
var products = [Product]()
let prodCollection: RestaurantDetails
let sections = [["Burgers", "Fries", "Cola", "Chicken", "Sides"],["Breakfast", "Lunch", "Dinner"]]
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.white
self.initViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initViews()
}
#IBAction func confirmButtonClicked(_ sender: Any) {
self.normalSelected(at: 1)
self.hideMenu()
}
#IBAction func cancelButtonClicked(_ sender: Any) {
// self.changeMenu(title: "Changed", at: 1)
// self.changeMenu(title: "Changed", status: .selected, at: 0)
self.alwaysSelected(at: 1)
// self.alwaysSelected(at: 2)
// self.alwaysSelected(at: 3)
self.hideMenu()
}
override func dropDownViewOpened() {
print("Open Menu")
}
override func dropDownViewClosed() {
print("Close Menu")
}
func initViews() {
}
}
extension PickerFilterClass: UIPickerViewDataSource, UIPickerViewDelegate {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return sections[component].count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
pickerView.sizeToFit()
return sections[component][row]
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let view = UIView()
view.frame = CGRect(x: 10, y: 20, width: 300, height: 52)
let label = UILabel()
label.frame = CGRect(x: 0, y: 0, width: 300, height: 52)
label.textAlignment = .center
label.font = UIFont(name: "Tiny.Toon", size: 11)
label.textColor = UIColor.purple
label.text = sections[component][row]
view.addSubview(label)
// view rotation
// view.transform = CGAffineTransform(rotationAngle: 90 * (.pi/180))
return view
}
I am trying to use the pickerview to access this collection view here:
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
print(sections[row])
if sections.count > row {
let selectedUsage = sections[component][row].lowercased()
if (selectedUsage == RestaurantDetails.allProductIdentifier.lowercased()) {
filteredProducts = products
} else {
filteredProducts = products.filter { ($0.usage?.lowercased() ?? "") == selectedUsage }
}
self.prodCollection.productCollection.reloadData()
}
}
}

How to change UIPickerViewData when I select the different UITextField?

I want to show a UIPickerView when tapping a UITextField.
And I made a 'place' UITextField with a UIPickerView.
But, I don't know how to make another UITextField with a UIPickerView.
I tried to use 'switch', but UITextField was not a value, so I couldn't do it with 'switch'.
I want to change UIPickerViewData when I select the different UITextField.
How can I do?
Here's the codes.
Thank you!
#IBOutlet weak var place: UITextField!
#IBOutlet weak var product: UITextField!
#IBOutlet weak var number: UITextField!
let placeArray = ["A", "B", "C", "D", "E", "F"]
let productArray = ["Apple", "Banana", "Grape"]
let numberArray = ["1", "2", "3", "4", "5", "6"]
var pickerView = UIPickerView()
var textField: UITextField!
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return placeArray.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
place.text = placeArray[row]
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return placeArray[row]
}
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(displayPickerView))
tapGesture.numberOfTapsRequired = 1
place.addGestureRecognizer(tapGesture)
}
#objc private func displayPickerView() {
if textField == nil {
self.textField = UITextField(frame: .zero)
textField.inputView = self.pickerView
self.view.addSubview(textField)
}
textField.becomeFirstResponder()
}
Very simple way to do this.
var placePickerView = UIPickerView()
var productPickerView = UIPickerView()
var numberPickerView = UIPickerView()
override func viewDidLoad() {
super.viewDidLoad()
placePickerView.delegate = self
placePickerView.dataSource = self
place.inputView = placePickerView
productPickerView.delegate = self
productPickerView.dataSource = self
product.inputView = productPickerView
numberPickerView.delegate = self
numberPickerView.dataSource = self
number.inputView = numberPickerView
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
var numberOfRows: Int = 1
if pickerView == placePickerView {
numberOfRows = placeArray.count
} else if pickerView == productPickerView {
numberOfRows = productArray.count
} else if pickerView == numberPickerView {
numberOfRows = numberArray.count
}
return numberOfRows
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == placePickerView {
place.text = placeArray[row]
} else if pickerView == productPickerView {
productType.text = productArray[row]
} else if pickerView == numberPickerView {
transactionType.text = numberArray[row]
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
var title: String?
if pickerView == placePickerView {
title = placeArray[row]
} else if pickerView == productPickerView {
title = productArray[row]
} else if pickerView == numberPickerView {
title = numberArray[row]
}
return title
}