I have a UITableView, its top and bottom distance to superview is 0.
When keyboard appears I update the bottom constraint, so that keyboard will not hide the table. But on updating the bottom constraint, last two or three cells are not completely visible. I am using following code to update the bottom constraint.
func keyboardWillChangeFrameWithNotification(notification: NSNotification, showsKeyboard: Bool) {
let userInfo = notification.userInfo!
let animationDuration: NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
// Convert the keyboard frame from screen to view coordinates.
let keyboardScreenBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
if showsKeyboard
{
cntInputViewBottom.constant = keyboardScreenBeginFrame.size.height
}
else
{
cntInputViewBottom.constant = 0
}
}
You are using UIKeyboardFrameBeginUserInfoKey. This is size of the keyboard at the beginning of frame change animation. You should better use UIKeyboardFrameEndUserInfoKey in order to get final frame.
if x is the height of the view with send button.
if showsKeyboard
{
cntInputViewBottom.constant = keyboardScreenBeginFrame.size.height+ x
}
else
{
cntInputViewBottom.constant = x
}
Problem is you are not informing your view/controller to update your constraint before and after.
if showsKeyboard
{
self.view.layoutIfNeeded()
cntInputViewBottom.constant = keyboardScreenBeginFrame.size.height
self.view.layoutIfNeeded()
}
else
{
self.view.layoutIfNeeded()
cntInputViewBottom.constant = 0
self.view.layoutIfNeeded()
}
just add self.view.layoutIfNeeded() before & after updating constraint as displayed.
Related
View is initialized with following constraints
View.snp.makeConstraints { (para) in
View.topConstraint = para.top.equalTo(parentview.snp.top).constraint
View.LeadingConstraint = para.leading.equalTo(parentview.snp.leading).constraint
View.TrailingConstraint = para.trailing.equalTo(parentview.snp.trailing).constraint
View.BottomConstraint =para.bottom.equalTo(parentview.snp.bottom).offset(-getheight).constraint
}
where getheight = parentview.frame.size.height/2 ;
when parentview changes its dimensions.View doesnt update its height as constraints are not called again.
any way to update or recall its constraints other the remakingConstraint which is not feasible at large scale.
Have tried:
View.updateConstraints()
View.setNeedsUpdateConstraints()
View.setNeedsLayout()
I need reference to each constraints because
if View.bottomTouch {
View.bottomConstraint.update(offset: View. BottomConstraint.layoutConstraints[0].constant + CurrentPoint - PreviousPoint)
}
Is there a reason you don't want to use 50% of the parent view height?
View.snp.makeConstraints { (para) in
para.top.equalTo(parentview.snp.top)
para.leading.equalTo(parentview.snp.leading)
para.trailing.equalTo(parentview.snp.trailing)
// 50% of the parent view height
para.height.equalTo(parentview.snp.height).multipliedBy(0.5)
// instead of this
//para.bottom.equalTo(parentview.snp.bottom).offset(-getheight)
}
Edit - after comments...
Keeping a reference to a constraint for the purposes of dragging a view is a very different question from "Keep the child view at 50% of the height of the parent view."
Give this a try...
It will create a cyan "parentView" with a blue "childView" (subview). Dragging the blue view (Pan Gesture) will drag its bottom up / down. Tapping anywhere (Tap Gesture) will toggle the insets on the frame of the parentView between 20 and 60.
When the parentView frame changes - either from the tap or, for example, on device rotation - the "childView" bottom will be reset to 50% of the height of the "parentView":
class ViewController: UIViewController {
let parentView = UIView()
let childView = UIView()
// childView bottom constraint
var bc: Constraint!
override func viewDidLoad() {
super.viewDidLoad()
parentView.backgroundColor = .cyan
childView.backgroundColor = .blue
parentView.addSubview(childView)
view.addSubview(parentView)
parentView.snp.makeConstraints { para in
para.top.leading.trailing.bottom.equalTo(self.view.safeAreaLayoutGuide).inset(20.0)
}
// childView's bottom constraint offset will be set in viewDidLayoutSubviews()
childView.snp.makeConstraints { para in
para.top.leading.trailing.equalToSuperview()
bc = para.bottom.equalToSuperview().constraint
}
let p = UIPanGestureRecognizer(target: self, action: #selector(panHandler(_:)))
childView.addGestureRecognizer(p)
let t = UITapGestureRecognizer(target: self, action: #selector(tapHandler(_:)))
view.addGestureRecognizer(t)
}
#objc func tapHandler(_ g: UITapGestureRecognizer) -> Void {
// on tap, toggle parentView inset
// between 20 and 60
// this will trigger viewDidLayoutSubviews(), where the childView bottom
// constraint will be reset to 50% of the parentView height
var i: CGFloat = 60.0
if parentView.frame.origin.x > 20 {
i = 20.0
}
parentView.snp.updateConstraints { para in
para.top.leading.trailing.bottom.equalTo(self.view.safeAreaLayoutGuide).inset(i)
}
}
#objc func panHandler(_ g: UIPanGestureRecognizer) -> Void {
let translation = g.translation(in: g.view)
// update bottom constraint constant
bc.layoutConstraints[0].constant += translation.y
// reset gesture translation
g.setTranslation(CGPoint.zero, in: self.view)
}
var parentViewHeight: CGFloat = 0.0
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// reset childView's bottom constraint
// to 50% of its superView's height
// ONLY if parentView frame height has changed
if parentView.frame.height != parentViewHeight {
parentViewHeight = parentView.frame.height
bc.layoutConstraints[0].constant = -parentViewHeight * 0.5
}
}
}
Firstly, check whether the getheight value did update when the parent view layout change. In order to reload the existing constraints, you may need to call layoutIfNeeded() of your parent view.
So, I have a webview and its content font can increase/decrease by the slider. When I slide up the font size is increasing as well as the webview constraint to fit the content. But when I slide down, the constraint still at the last state when I slide up, it won't change, but the font decrease. So I have a lot of empty space because the height constraint doesn't change.
#objc func changeFontSize(_ sender: UISlider!) {
let webViewSize = 16 * sender.value
let jsString = "document.getElementsByTagName('body')[0].style.fontSize='\(webViewSize)px'"
webView.stringByEvaluatingJavaScript(from: jsString)
webViewDidFinishLoad(webView)
}
func webViewDidFinishLoad(_ webView: UIWebView) {
let webViewTextSize = webView.sizeThatFits(CGSize(width: 1.0, height: 1.0))
var webViewFrame = webView.frame
webViewFrame.size.height = webViewTextSize.height
webView.frame = webViewFrame
webHeightConstraints.constant = webViewTextSize.height
webView.scrollView.isScrollEnabled = false
webView.scrollView.bounces = false
}
That is my code, and I've tried to changed webHeightConstraints.constant to webview.scrollView.contentSize.height but got the same result. All the other values are changed according to the slider, only the height constraint. It changes only when the slides up, and then remain at that value.
I also face same kind of issue. try to clear webview when slide up and down, that will work here is code for clear webview.
final class WebCacheCleaner {
class func clear() {
URLCache.shared.removeAllCachedResponses()
HTTPCookieStorage.shared.removeCookies(since: Date.distantPast)
WKWebsiteDataStore.default().fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in
records.forEach { record in
WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {})
print("[WebCacheCleaner] Record \(record) deleted")
}
}
}
}
call like this WebCacheCleaner.clear()
Im using SnapKit to alter the height of a UIView based on a touch event. So when the user touches the cell it expands. This works fine like this:
#objc func didRecieveTouch() {
let originalHeight: CGFloat = 90
let expandedHeight: CGFloat = 244
if !expanded {
self.snp.updateConstraints { make in
make.height.equalTo(expandedHeight)
}
} else {
self.snp.updateConstraints { make in
make.height.equalTo(originalHeight)
}
}
self.expanded = !self.expanded
UIView.animate(withDuration: 0.25, animations: {
self.superview?.layoutIfNeeded()
})
}
The problem is that the direction the view grows in looks weird and wrong to me. The view actually "hops" down to the new allocated space and grows upwards instead of growing downwards which is the desired behaviour I want.
Add your code inside the animation block.
UIView.animate(withDuration: 0.25) {
if !expanded {
self.snp.updateConstraints { make in
make.height.equalTo(expandedHeight)
}
} else {
self.snp.updateConstraints { make in
make.height.equalTo(originalHeight)
}
}
self.expanded = !self.expanded
self.superview?.layoutIfNeeded()
}
I'm using Xcode 9 and Swift 4. I'm having trouble trying to use the scroll in y to hide SearchBar through alpha. How to access this background to try to hide it?
code:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let transp:Float = Float(1 - (self.mTableView.contentOffset.y / (self.mTableView.contentSize.height - self.mTableView.frame.size.height) * 60))
self.navigationController!.navigationBar.alpha = CGFloat(transp)
self.mSearchController.searchBar.alpha = CGFloat(transp)
self.mSearchController.searchBar.isTranslucent = true
titleMsgView.alpha = CGFloat(transp)
}
Here's a sample gif link:
https://www.dropbox.com/s/6is5mukpk1yew8e/bgSearch.gif?dl=0
The SearchView is pretty tough when it comes to changing how it looks. You could try looping over the subviews of the SearchView and setting all their alpha values to 0, like this:
for subView in mSearchController.searchBar.subviews {
subView.alpha = 0
for deepSubView in subView.subviews {
deepSubView.alpha = 0
}
}
Also, a quick note: you can remove a lot of the self keywords from your code.
EDIT: That just removed the searchbar, but with some editing we can fix that:
for subview in mSearchController.searchBar.subviews.last!.subviews {
if type(of: subview) == NSClassFromString("UISearchBarBackground") {
subview.alpha = 0
}
}
That should do the trick!
I am trying to calculate the position to move a UITextField along with its parent UIView if the keyboard is overlapping the field and move back to its original position after keyboard is closed.
I have already tried https://github.com/hackiftekhar/IQKeyboardManager and it does not work in my particular case.
To explain the problem, please refer two attached screenshot, one when keyboard is opened and another when it is closed.
As you can see, on keyboard open, the text field is overlapping the keyboard, I want to move the text field along with popup view to readjust and sit above the keyboard.
Here is what I tried.
func textFieldDidBeginEditing(_ textField: UITextField) {
self.startOriginY = self.frame.origin.y
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
}
#objc func keyboardWillShow(_ notification: Notification) {
if let keyboardFrame: NSValue = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
let screenHeight = self.backgroundView.frame.height
let viewHeight = self.frame.height
let diffHeight = screenHeight - viewHeight - keyboardHeight
if diffHeight < 0 {
self.frame.origin.y = -self.textField.frame.height
}
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.frame.origin.y = self.startOriginY
}
This code moves the view to incorrect position. I am trying to figure out how to calculate the correct position to move the view and remove keyboard overlap.
What is the best way to go about solving this problem?
Thank you.
Basically you need to embedded your view inside a scroll view and use Apple's example to handle the adjustment by altering the bottom content inset of the scroll view:
Embedded inside a scroll view
Register for keyboard notifications
Implement logic to handle the notifications by altering the bottom content inset
I have converted Apple's code snipe to Swift.
Keyboard will show:
if let info = notification.userInfo,
let size = (info[UIKeyboardFrameEndUserInfoKey] as AnyObject?) {
let newSize = size.cgRectValue.size
let contentInset = UIEdgeInsetsMake(0.0, 0.0, newSize.height, 0.0)
scrollView.contentInset = contentInset
}
Keyboard will hide:
let contentInset = UIEdgeInsets.zero
scrollView.contentInset = contentInset
scrollView.scrollIndicatorInsets = contentInset
You can also add hard-coded offset to the newSize.height i.e: newSize.height + 20