I have customized my trailing swipe action for UITableViewCell. It has an image along with title and background color. It has been done like this :
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .normal, title: ActionTitle.delete) { (deleteAction, view, handler) in
self.deleteAction(indexPath: indexPath)
return handler(true)
}
deleteAction.image = Common.getImageAndTitleForTableRowAction(title: ActionTitle.delete, actionImage: #imageLiteral(resourceName: "delete"))
deleteAction.backgroundColor = Color.orangeColor
let editAction = UIContextualAction(style: .normal, title: ActionTitle.edit) { (editAction, view, handler) in
self.selectedIndexPath = indexPath
self.editLoanRecord()
return handler(true)
}
editAction.image = Common.getImageAndTitleForTableRowAction(title: ActionTitle.edit, actionImage: #imageLiteral(resourceName: "edit"))
editAction.backgroundColor = Color.blueColor
return UISwipeActionsConfiguration(actions: [deleteAction, editAction])
}
Now I need to set the backgroundColor to a gradient.
Checked lots of questions on stackoverflow but unable to do so. Any help will be appreciated.
You could try to create a color from a gradient image like so :
func linearGradientColor(from colors: [UIColor], locations: [CGFloat], size: CGSize) -> UIColor {
let image = UIGraphicsImageRenderer(bounds: CGRect(x: 0, y: 0, width: size.width, height: size.height)).image { context in
let cgColors = colors.map { $0.cgColor } as CFArray
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(
colorsSpace: colorSpace,
colors: cgColors,
locations: locations
)!
context.cgContext.drawLinearGradient(
gradient,
start: CGPoint(x: 0, y: 0),
end: CGPoint(x: size.width, y:0),
options:[]
)
}
return UIColor(patternImage: image)
}
...
deleteAction.backgroundColor = linearGradientColor(
from: [.red, .blue],
locations: [0, 1],
size: CGSize(width: 100, height: 44)
)
But this code has some limitations. You can not guess the size of the action view. So depending on your needs, you can either repeat the color, stretch it or use a large image. Using a third party lib is also a good option.
In many cases, Apple's default implementations will only take you so far and any further customization requires re-implementing the feature.
This seems like one of those cases, since the contextual action is not a view, so you can't modify it to add a gradient like you would with other views, and its properties are limited.
Your options are: implement your own swiping cell, use a third party library (like this one), or simply use a solid color.
Related
I have a problem with implementing custom animation while swiping table view cell.
The goal is to change cell background color while swipe cell with animation.
Ideally, it's perfect if background color changes depending on the offset on the x-axis.
Or if it's impossible or difficult to do it, it would be good to finish the animation when swiping is finished.
And the background color of the cell should be the same as the action button's one.
"Swiping" means gesture that makes buttons show like as default delete action.
The follow code is current one.
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let action = UIContextualAction(style: .normal, title: "", handler: { (action,view,completionHandler ) in
completionHandler(true)
})
action.image = UIGraphicsImageRenderer(size: CGSize(width: 30, height: 30)).image { _ in
UIImage(named:"sell_btn")?.draw(in: CGRect(x: 0, y: 0, width: 30, height: 30))
}
action.backgroundColor = UIColor(hex: "#F4F4F4")
tableView.backgroundColor = .red
let confrigation = UISwipeActionsConfiguration(actions: [action])
return confrigation
}
This code changes the background color when this function called.
PS: I've tried MGSwipeCell and SwipeCellKit too, but they don't provide me exact thing what I want.
Thanks.
I am trying to add Trailing Swipe Actions for UITableView using UIContextualAction but the icon is not visible because the icon becomes white and the background is also white and when I change the background color it is visible. Please help me set the icon as such with its color. I tried searching for tint color property but there is no such property. Below are the codes I have tried.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .normal, title: nil, handler: { (action,view,completionHandler ) in
// Delete the row after API
})
//Solution 1
delete.image = UIImage(named: "deleteicon")
// Solution 2
delete.image = UIGraphicsImageRenderer(size:CGSize(width: 30, height: 30)).image { _ in
UIImage(named:"deleteicon")?.draw(in: CGRect(x: 0, y: 0, width: 30, height: 30))
}
// Solution 3
edit.backgroundColor = UIColor(patternImage: UIGraphicsImageRenderer(size:CGSize(width: 30, height: 30)).image { _ in UIImage(named:"favouriteinactiveicon")?.draw(in: CGRect(x: 0, y: 0, width: 30, height: 30))})
let confrigation = UISwipeActionsConfiguration(actions: [delete])
return confrigation
}
I am trying to use tableView:editActionsForRowAt:, having buttons with images instead of the usual texts.
But there are some challenges. Can some one help me?
First here is what I have already working, -- with some precious help from SOF --
and here is what I would like to get ideally:
The relevant code is below. The first case above is obtained when having xShift and xShiftInc both set to 0.0.
The second case is obtained by initializing xShift to 30.0 and xShiftInc to 20.0.
Graphically I get the result I want, but the problem is that the touch areas for the buttons have not moved as the image. In other words in the second case, if I touch the trash it prints "upBtn touched!".
To get "rmvBtn touched!" printed I need touch at the left of the trash.
Beside, I am not very happy with using 46.0 for the height of the cell, I would like a more generic parameter (rowHeigh equals -1 so can't be used). But this is a different issue.
func tableView(_ tableView: UITableView,
editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
var patternImg:UIImage?, xShift = CGFloat(30.0)//CGFloat(0.0)//
let xShiftInc = CGFloat(20.0)//CGFloat(0.0)//
let downBtn = UITableViewRowAction(style: .normal, title: "") {
action, index in
print("downBtn touched!")
}
patternImg = swipeCellImage(named: "DownIcn", side: 46.0, horizOffSet: xShift)
downBtn.backgroundColor = UIColor(patternImage: patternImg!)
let upBtn = UITableViewRowAction(style: .normal, title: "") {
action, index in
print("upBtn touched!")
}
xShift += xShiftInc
patternImg = self.swipeCellImage(named: "UpIcn", side: 46.0, horizOffSet: xShift)
upBtn.backgroundColor = UIColor(patternImage: patternImg!)
let rmvBtn = UITableViewRowAction(style: .destructive, title: "") {
action, index in
print("rmvBtn touched!")
}
xShift += xShiftInc
patternImg = swipeCellImage(named: "TrashIcn", side: 46.0, horizOffSet: xShift)
rmvBtn.backgroundColor = UIColor(patternImage: patternImg!)
return [downBtn,upBtn,rmvBtn]
}
func swipeCellImage(named name: String, side: CGFloat, horizOffSet: CGFloat) -> UIImage? {
let theImage = UIImage(named: name)
UIGraphicsBeginImageContextWithOptions(CGSize(width: UIScreen.main.bounds.width,
height: side), false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(UIColor.clear.cgColor)
theImage?.draw(in: CGRect(x: horizOffSet, y: 0, width: side, height: side))
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
Simple logic..!! Manually we dont give xshift and xshiftinc.
Case 1:
let downBtn = UITableViewRowAction(style: .normal, title: "") {
action, index in
print("downBtn touched!")
}
Here title's text is "" [empty string with no spaces]
So, tableview automatically takes width 30px for each one. If we add text, it will increase it width sizes automatically.
Case 2:
let downBtn = UITableViewRowAction(style: .normal, title: " ") {
action, index in
print("downBtn touched!")
}
Here title's text is "" [empty string with 1 space]
So, tableview automatically takes width 35px for this.
Hope you understand above thing.
Now, I modified your code.
func tableView(_ tableView: UITableView,
editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let cell = tableView.cellForRow(at: indexPath) as! myTableViewCell
print("cell_height ", cell.frame.size.height) // U MAY GET ROW HEIGHT HERE
var patternImg:UIImage?
let downBtn = UITableViewRowAction(style: .normal, title: " ") {
action, index in
print("downBtn touched!")
}
patternImg = swipeCellImage(named: "down", rowHeight: cell.frame.size.height)
downBtn.backgroundColor = UIColor(patternImage: patternImg!)
let upBtn = UITableViewRowAction(style: .normal, title: " ") {
action, index in
print("upBtn touched!")
}
patternImg = self.swipeCellImage(named: "up", rowHeight: cell.frame.size.height)
upBtn.backgroundColor = UIColor(patternImage: patternImg!)
let rmvBtn = UITableViewRowAction(style: .destructive, title: " ") {
action, index in
print("rmvBtn touched!")
}
let patternIm = swipeCellImage(named: "trash", rowHeight: cell.frame.size.height)
rmvBtn.backgroundColor = UIColor(patternImage: patternIm!)
return [downBtn,upBtn,rmvBtn]
}
func swipeCellImage(name: String, rowHeight: CGFloat) -> UIImage? {
let imgYposition : CGFloat = (rowHeight - 30) / 2
// NOTE: This 30px is image height. Image height is always should be less than Rowheight.
let theImage = UIImage(named: name)
UIGraphicsBeginImageContextWithOptions(CGSize(width: UIScreen.main.bounds.width,
height: rowHeight), false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(UIColor.yellow.cgColor)
context!.fill(CGRect(x: 0, y: 0, width: (self.view.frame.width) / 3, height: side))
theImage?.draw(in: CGRect(x: 5, y: imgYposition, width: 30, height: 30))
// In this sample, am taking rowHeight as 44px.
// Images should be 30 * 30 sizes.
// I gave two spaces in title. So total width is 40px.
// So,x = 5px and y = 7px.
let resultImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return resultImage
}
Output
If you want to give more gap between three buttons, just increase title's empty text and calculate width and keep your image center.
Here is some trouble I am having working with a UITableView, more precisely using an image in tableView:editActionsForRowAt:
Below follows my relevant code. It may be useful to say that the images I am using here are all square 70x70.
func tableView(_ tableView: UITableView,
editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
var patternImg:UIImage?
let upBtn = UITableViewRowAction(style: .normal, title: "") {
action, index in
print("upBtn button tapped")
}
patternImg = self.swipeCellImage(named: "UpIcn", side: 46.0)
upBtn.backgroundColor = UIColor(patternImage: patternImg!)
let downBtn = UITableViewRowAction(style: .normal, title: "") {
action, index in
print("downBtn button tapped")
}
patternImg = swipeCellImage(named: "DownIcn", side: 46.0)
downBtn.backgroundColor = UIColor(patternImage: patternImg!)
let rmvBtn = UITableViewRowAction(style: .destructive, title: "") {
action, index in
print("rmvBtn button tapped")
}
patternImg = swipeCellImage(named: "TrashIcn", side: 46.0)
rmvBtn.backgroundColor = UIColor(patternImage: patternImg!)
return [downBtn,upBtn,rmvBtn]
}
func swipeCellImage(named name: String, side: CGFloat) -> UIImage? {
let theImage = UIImage(named: name)
UIGraphicsBeginImageContextWithOptions(CGSize(width: side*2, height: side), false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(UIColor.clear.cgColor)
theImage?.draw(in: CGRect(x: 0, y: 0, width: side, height: side))
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
Things work, but unfortunately only up to a certain point.
Looking at this screen shot shows that there is an unwanted repetion of the images. Clearly I want each button(Icon) to only appear one time each.
Can anyone see how I need to fix my code to avoid this repetion?
To avoid that, you have to increase width size asper your requirement.
UIGraphicsBeginImageContextWithOptions(CGSize(width: self.view.frame.width, height: commonHei), false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
context!.setFillColor(textColor.cgColor) // CHECK BY CHANGE BGCOLOR
context!.fill(CGRect(x: 0, y: 0, width: (self.view.frame.width) / 3, height: commonHei)) // INCREASE WIDTH SIZE
var img: UIImage = UIImage(named: "pause")!
img.draw(in: CGRect(x: 0, y: 0, width: 30, height: 30)) // Change position as per ur requirement.
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
If you having more doubt, then check on the 3D view.
I'm using Swift 3.0 with Xcode 8 and I'm having some problems with image resizing. Here is the code where i set my UIImage frame.
open func setData(_ data: Any?, image: String) {
self.textLabel?.font = UIFont.boldSystemFont(ofSize: 10)
self.textLabel?.textColor = UIColor(hex: "000000")
if let menuText = data as? String {
self.textLabel?.text = menuText
}
self.imageView?.contentMode = UIViewContentMode.scaleToFill
self.imageView?.frame = CGRect(x: 12, y: 8, width: 10, height: 10)
self.imageView?.image = UIImage(named: image)
self.imageView?.clipsToBounds = true
}
And here is where I call my function inside my tableView. I don't have any problem with setting the image, but ONLY with resize. When i use smaller images, the image is smaller, when i use bigger images, the image gets bigger, it doesnt resize.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = BaseTableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: BaseTableViewCell.identifier)
cell.setData(menus[indexPath.row], image: images[indexPath.row])
return cell
}
I have solved it by using this resize function to resize my image and then place in the ImageView
func imageResize(image:UIImage,imageSize:CGSize)->UIImage
{
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0.0)
[image .draw(in: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))]
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
return newImage!
}
If you are using default image view of uitableview cell than you won't be able to resize it. Some default constraints are already there.
You have two options :
create a subclass of uitableview cell and use your own image view (don't create the outlet with name imageView, try something else).
Resize the image using https://stackoverflow.com/a/45100626/5383852