Using buttons/images in tableView:editActionsForRowAt: - ios

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.

Related

UITableViewCell - Set background as gradient to Delete (Swipeable Action) - Swift 4.2

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.

Add Trailing Swipe Actions Configuration with white background color and dark gray icon

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
}

Working with images in tableView:editActionsForRowAt:

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.

UICollectionView Data not displaying correctly

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: MaterialCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! MaterialCollectionViewCell
let item = items()[indexPath.item]
//print(cell.contentView.subviews)
for view in cell.contentView.subviews{
view.removeFromSuperview()
}
//print(cell.contentView.subviews)
let colors = [UIColor.grayColor(), UIColor.darkGrayColor()]
cell.backgroundColor = colors[indexPath.item % 2]
let showTitle: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height))
showTitle.text = item.title
showTitle.textAlignment = .Center
showTitle.font = UIFont(name: "HelveticaNeue", size: 25.0)
showTitle.textColor = MaterialColor.white
showTitle.center = cell.center
showTitle.hidden = true
//print(showTitle.text)
cell.contentView.addSubview(showTitle)
let imageView: UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height))
imageView.kf_setImageWithURL(NSURL(string: item.banner)!,
placeholderImage: nil,
optionsInfo: nil,
progressBlock: { (receivedSize, totalSize) -> () in
//print("Download Progress: \(receivedSize)/\(totalSize)")
},
completionHandler: { (image, error, cacheType, imageURL) -> () in
//print("Downloaded and set!")
if (image != nil) {
showTitle.removeFromSuperview()
}
else {
showTitle.hidden = false
}
}
)
cell.contentView.addSubview(imageView)
//print(cell.contentView.subviews)
return cell
}
this is the code I am using to display data into show title label. For the moment imageView doesn't ever show
issue with mine is the complete data is not displayed instead a part of it
current output
Should have shown these in the same order
Game of Thrones
Orange Is the New Black
Marco Polo (2014)
Person of Interest
Dark Matter
I think the problem is that the UILabel view and the UIImageView are overlapped 。 You should shrink the size of UILabel, and put the UIImageView behind the UILabel.

Dynamically changing CollectionView Cell Size Based on Downloaded Images Using Swift

I'm trying to build a collection view layout like Pinterest uses. Most of what is out there is in Objective C, so I've used this RW tutorial: http://www.raywenderlich.com/107439/uicollectionview-custom-layout-tutorial-pinterest
The problem is that the app in the RW tutorial uses local images, whereas I'm trying to base the cell size on images that are downloaded via PinRemoteImage but I cannot get the collectionView to properly lay itself out again once the images are downloaded.
Below is my attempt to modify the extension:
extension PinCollectionViewController : PinterestLayoutDelegate {
// 1
func collectionView(collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath: NSIndexPath,
withWidth width: CGFloat) -> CGFloat {
var pinterestLargestImage = UIImage()
if imageDownloads == 0 {
pinterestLargestImage = imageArray[indexPath.row]
} else {
pinterestLargestImage = UIImage(named: "testPic")!
}
let boundingRect = CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT))
let rect = AVMakeRectWithAspectRatioInsideRect(pinterestLargestImage.size, boundingRect)
return rect.size.height
}
// 2
func collectionView(collectionView: UICollectionView,
heightForAnnotationAtIndexPath indexPath: NSIndexPath, withWidth width: CGFloat) -> CGFloat {
var pinterestLargestImage = UIImage()
if pins.count == imageArray.count {
pinterestLargestImage = imageArray[indexPath.row]
} else { pinterestLargestImage = UIImage(named: "testPic")!}
let annotationPadding = CGFloat(4)
let annotationHeaderHeight = CGFloat(17)
let font = UIFont(name: "AvenirNext-Regular", size: 10)!
let commentHeight = CGFloat(10.0)
let height = annotationPadding + annotationHeaderHeight + commentHeight + annotationPadding
return height
}
}
Then I've tried to call self.collectionView(self.collectionView!, layout: (self.collectionView?.collectionViewLayout)!, sizeForItemAtIndexPath: indexPath) and self.collectionView!.reloadItemsAtIndexPaths([indexPath]) inside cellForRowAtIndexPath once the cell's image is downloaded, but neither properly call these methods to adjust the layout. Can anyone point me in the right direction here?

Resources