Is it possible to fix the position of a UITableViewController background image?
I've added the background image via the viewdidload method with the following code -
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"blurredBGW"]];
But as the table is fairly long (and also contains static cells if that matters) it scrolls (and repeats) as you scroll down the table.
you can try to add the background image as UIView and not as UIColor, try this:
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"blurredBGW.png"]];
for swift version 3.0.try this code.it will set a fixed background to a table view controller
self.tableView.backgroundView = UIImageView(image: UIImage(named: "background.png")!)
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"bg.png"]];
[tempImageView setFrame:self.tableView.frame];
self.tableView.backgroundView = tempImageView;
Make the background of your table (and the cells) transparent, and set the image for the view underneath the table.
for
swift 2.2
you may use the following line of code
self.tableView.backgroundView = UIImageView(image: UIImage(named: "xxxx.png"))
I prefer to configure background with creating its specific xib, because background can be difficult. I do next:
1) Create a class, that helps me to load nib
class UIXIBView: UIView {
var view: UIView!
func setupXIBWithName(_ nibName: String) {
view = self.getViewFromNibWithName(nibName)
self.addSubview(view)
view.frame = self.bounds
view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
}
func getViewFromNibWithName(_ nibName: String) -> UIView {
let bundle = Bundle.main
let views = bundle.loadNibNamed(nibName, owner: self, options: nil)! as [AnyObject]
let view = views[0] as! UIView
return view
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setupXIBWithName(String(describing: type(of: self)))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupXIBWithName(String(describing: type(of: self)))
}
}
2) I create your specific view, for example let it be LKBackgroundView.swift, and inherit it from UIXIBView
class LKBackgroundView: UIXIBView {
// You can add your own logic there or override smth
}
3) I create xib with the same name LKBackgroundView.xib
4) I set FileOwner's class to LKBackgroundView inside xib, don't make a mistake by setting LKBackgroundView to the view class
5) Configure you xib like you want
6) Initialize your view inside ViewDidLoad inside your View Controller
override func viewDidLoad() {
super.viewDidLoad()
LKBackgroundView(frame:tableView.bounds)
tableView.backgroundView = backgroundView
}
7) Test it
Xamarin/C# Solution
TableView.BackgroundView = new UIImageView(UIImage.FromBundle("blurredBGW"))
Related
I want to add and remove views at runtime in a stack view but am not able to do it.
Basically the situation is I am using a Button made from a Xib and adding it to a StackView, Stack View Distribution is fill equally and alignment is fill but the problem is that the button is not resizing according to the stack view.
I mean if I give initialiser a frame rect .zero then it's invisible, If I give it a CGRect(0,0,40,40) then it's a 40x40 square but don't resizes properly.
The main confusion and problem is it looks as expected in View Hierarchy Debugger but results on simulator don't translates in the same way attached some screenshots for reference and I also added some blank UIView and they are working as expected.
Code for rendering in ViewController
func render(viewModel: ViewModel) {
let rentalButton = MyCustomButton(frame: .zero)
let shiftingButton = MyCustomButton(frame: .zero)
rentalButton.titleText = "Rental button"
shiftingButton.titleText = "Shifting button"
rentalButton.subtitleText = "subtitle rental"
shiftingButton.subtitleText = "subtitle shifting"
for view in stackView.arrangedSubviews {
stackView.removeArrangedSubview(view)
view.removeFromSuperview()
}
let black = UIView()
black.backgroundColor = .black
let red = UIView()
red.backgroundColor = .red
stackView.addArrangedSubview(shiftingButton)
stackView.addArrangedSubview(black)
stackView.addArrangedSubview(rentalButton)
stackView.addArrangedSubview(red)
if viewModel.showRental && !viewModel.showHouseShifting {
rentalButton.showSubtitle = true
shiftingButton.showSubtitle = false
stackView.removeArrangedSubview(shiftingButton)
shiftingButton.removeFromSuperview()
}
else if !viewModel.showRental && viewModel.showHouseShifting {
rentalButton.showSubtitle = false
shiftingButton.showSubtitle = true
stackView.removeArrangedSubview(rentalButton)
rentalButton.removeFromSuperview()
}
stackView.layoutIfNeeded()
rentalButton.layoutIfNeeded()
}
Init Code for my Button from Xib
override init(frame: CGRect) {
super.init(frame: frame)
self._init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
self._init()
}
private func _init() {
Bundle.main.loadNibNamed("MyCustomButton", owner: self, options: nil)
self.addSubview(self.contentView)
self.contentView.frame = self.bounds
self.contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
setTitle(nil, for: .normal)
self.matchConstraints(toView: contentView)
decorate()
}
I usually use autolayout together with size classes, to optimize the UI for larger screens, like on iPad.
However, sometimes I need a completely different layout for the UI on iPad, still containing the same view controllers, but structured differently.
What is the best strategies in such situation, where autolayout and size classes are not enough? Loading a different storyboard for iPad?
Obviously the goal here is to not introduce any code duplication.
thanks
Loading a different storyboard for iPad? Obviously the goal here is to not introduce any code duplication.
If that's what you want to do, that feature is built-in and expected. You don't need any code at all. Just create your two storyboards and edit the Info.plist so that it has two main storyboard entries that point to them:
The right thing will just happen: on iPad, the second storyboard will load at launch.
I do same thing with size classes on UIViews and NSLayoutConstraints, for an example if i have different views for pad and phone, but i must do same logic for sections, i create two different views in same storyboard and enable/disable views based on size classes
Make Use of 2 Views(xib) with a single class file. The number of connections has to be same in both xibs but the placement of elements can be different for iPad and iPhone.
Here Below is my code to load XIB from a viewcontroller.
class ViewController: UIViewController {
var customView:CustomView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
loadCustomView()
}
func loadCustomView(){
if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
let window = appDelegate.window {
customView = CustomView(frame: CGRect(x: 0, y: 0, width: window.frame.width, height: window.frame.height))
window.addSubview(customView!)
}
}
}
Then there is the UIView Class
import UIKit
class CustomView: UIView {
#IBOutlet weak var lbl_Title: UILabel!
var view:UIView!
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setup()
}
func setup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = UIView.AutoresizingMask.flexibleWidth
view.autoresizingMask = UIView.AutoresizingMask.flexibleHeight
addSubview(view)
}
func loadViewFromNib() -> UIView {
if UIDevice.current.userInterfaceIdiom == .phone{
let bundle = Bundle(for:type(of: self))
let nib = UINib(nibName: "CustomView", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}else{
let bundle = Bundle(for:type(of: self))
let nib = UINib(nibName: "CustomViewTab", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
}
}
You make the outlet connections to both the XIBs from this class and load the views depending on device type.
So I am in a mildly complicated situation,
The issue: There is a thin blue line that goes across my Custom UITableViewSectionHeader only when under navigation bar that I do not know where is coming from:
I have:
A tableview nested inside a UIViewController
A GradientView (inherits UIView) directly under my NavigationBar
A TableView that overlaps my GradientView
A Custom TableViewSectionHeader Class (Subclass UITableViewCell)
[
My theory:
That border line is either from:
- The bottom border of navigation bar
- The top border of tableview
- Maybe a separator from the Section header (but seems unlikely)
- A bottom border from the GradientView
Anybody have an idea what could be causing that line?
I have tried to remove it with:
ViewController:
override func viewDidLoad() {
// self.tableview.separatorStyle = .none
// self.tableview.layer.borderWidth = 0
// self.view.layer.borderWidth = 0
}
GradientView:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.borderWidth = 0
}
SectionHeader:
self.separatorInset.left = 1000
self.layer.borderWidth = 0
Any thoughts?
Navigation bars has an image view with a line which is somewhere between less than or equals to 1px you have to loop through NavigationController navigationBar to find that imageView and set that to hidden.
You can directly loop on navigationBar and find all subViews or if you want to have a reference to the view then here how I would have done it.
var lineImageView: UIImageView? = { [unowned self] in
// guard is great try to use it whenever you can
guard let navigationBar = self.navigationController?.navigationBar else {
return nil
}
return self.findLineImageView(for: navigationBar)
}()
now add this function which loops through till it finds an imageView and return it back to our lineImageView
// remember even **navigationBar** is a UI remember **UINavigationBar**
func findLineImageView(for view: UIView) -> UIImageView? {
// as I said above the line is not more than 1px so we look for a view which is less than or equals to 1px in height
if view is UIImageView && view.bounds.size.height <= 1 {
return (view as! UIImageView)
}
// we loop till we find the line image view and return it
for subview in view.subviews {
if let imageView = findLineImageView(for: subview) {
return imageView
}
}
// if there is no imageView with that height we return nil that's why we return an optional UIImageView
return nil
}
Now the magic part. in viewWillApear set the lineImageView to hidden
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// remember as I said the lineImageView we returned an optional that's why it has question mark which means we are safe
lineImageView?.isHidden = true
}
I have a scenario where in I need to create around 10 different prototypes of UITableViewCells. How ever all of these cells have some UI Elements (area marked in black) in common. And there is an area (marked in yellow) which is different for all these prototypes.
Is there a way I can abstract all the common UI Elements like the way it is done for contentView in UITableViewCell?
I tried to create a TableViewCell with all these elements and empty UIView to hold the customizations and planned to programatically load UIView (created in separate xib) into it.
The problem is I am not able to load the UIView into the UITableViewCell without loosing the constraints?
How to load a custom view with constraints into another?
Or Is there a way to create a custom UITableViewCell like the one in IB?
Create LoadableFromXibView subclass
Create a xib file, set the File's owner as your subclass
Drag outlets and design your view as usual
In your cell insert a subview that will be your reusable part of the cell and set its name as the new LoadableFromXibView subclass that you have created.
Source here: https://gist.github.com/DenHeadless/c3d682e7f499113109d6
class LoadableFromXibView: UIView {
var view = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
view = loadViewFromXib()
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
backgroundColor = .clearColor()
addSubview(view)
}
private func loadViewFromXib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: String(self.dynamicType), bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil).first as! UIView
return view
}
}
I am trying to apply background Image to all my screens in my iOs application.
My initial screen is a Registration screen where i want to apply the background image, the registration screen is as shown below:
I am using a custom UIView from xib file to apply the background image.
But after applying the background image it only shows the background image on the Registration screen and removes the login controls. I dont know why.
Following is the registration screen after applying the image background.
One more thing, I can see the background image only on the run time not in the Storyboard.
Following is my implementation
I have created one .xib file having a simple UIView, this UIView would serve as a master view in all my application. To obtain the UIView from nib file and to apply further settings I am using a custom UIView class. In this custom UIView class I am applying the background image on the UIView obtained from the nib file. As you can see above I am applying this custom UIView class to the Registration screen UIView. Following is the code as shown below:
class BackgroundMap: UIView {
var view: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
view = loadViewFromNib ()
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
view.translatesAutoresizingMaskIntoConstraints = true
view.backgroundColor = UIColor(patternImage: UIImage(named: "MapWantd")!)
self.addSubview(view)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
view = loadViewFromNib ()
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
view.translatesAutoresizingMaskIntoConstraints = true
view.backgroundColor = UIColor(patternImage: UIImage(named: "MapWantd")!)
self.addSubview(view)
}
func loadViewFromNib() ->UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "BackgroundMap", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}