Swift UITableView custom Cell ordering Drag Drop? - ios

i am trying to resort UITableView cell's by long press then drag and drop the cell , its not working when i use Custom cell view any idea why !
Here is the TableView viewcontroller :
override func viewDidLoad()
{
super.viewDidLoad()
// Then delegate the TableView
self.tableView.delegate = self
self.tableView.dataSource = self
// Register table cell class from nib
let bundle = Bundle(for: type(of: self))
let cellNib = UINib(nibName: "tbc_song_vertical", bundle: bundle)
self.tableView.register(cellNib, forCellReuseIdentifier: "tbc_song_vertical")
//Loading Template
let nib_tbc_loading = UINib(nibName: "tbc_loading", bundle: bundle)
self.tableView.register(nib_tbc_loading, forHeaderFooterViewReuseIdentifier: "tbc_loading")
//Automated ell height
self.tableView.estimatedRowHeight = 44.0
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.reloadData()
self.tableView.isEditing = true
}
// MARK: - Sorting
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .none
}
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedObject = self.data[sourceIndexPath.row]
data.remove(at: sourceIndexPath.row)
data.insert(movedObject, at: destinationIndexPath.row)
// To check for correctness enable: self.tableView.reloadData()
}
//loading footer
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = self.tableView.dequeueReusableHeaderFooterView(withIdentifier: "tbc_loading") as! tbc_loading
footerView.startAnimate()
return footerView
}
//loading footer
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return ( self.is_fetching ) ? 40 : 0
}
//Pagination
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
//Bottom Refresh
if scrollView == tableView{
if ((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height )
{
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell : tbc_song_vertical = tableView.dequeueReusableCell(withIdentifier: "tbc_song_vertical", for: indexPath) as! tbc_song_vertical
cell.fillwithInfo(dto: self.data[indexPath.row] )
return cell
}
// Tabbed Cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { }
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
}
only if i use custom view its not working , but when i hold my finger on the right side of any cell to drag it up or down its dragging all the table

Add the following method
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}

Related

Programmatically written cells of UITableView are in the same place

Interface:
Interface in debugger:
Here is configuration of tableview
private func configureTableView(){
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
// tableView.rowHeight = UITableView.automaticDimension
tableView.register(DishCell.self, forCellReuseIdentifier: "dishCell")
// tableView.sectionHeaderHeight = UITableView.automaticDimension
}
Here is tableView extensions
extension MenuViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 380
}
return 48
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 122
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableView.automaticDimension
}
}
extension MenuViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.dishes.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.dishes[section].count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let dishType = viewModel.dishTypes[section]
if section == 0 {
let restaurant = viewModel.restaurant
return FirstMenuHeader(restaurant: restaurant, dishType: dishType)
}else{
return DefaultMenuHeader(dishType: dishType)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dishCell") as! DishCell
let dish = viewModel.dishes[indexPath.section][indexPath.row]
cell.set(dish: dish)
return cell
}
}
Just to clarify DishCell, FirstMenuHeader and DefaultMenuHeader look well if you put them outside of UITableview. And they have constraints that define their height. However their height is dynamic and depends on amount of line of text.
Problem was in dishCell.I made constraints with view, while I had to make constraints with contentView.
I have rewrote my constraints and problem was resolved.

How can I make UITableViewCell stick to bottom when isEditing is enabled?

I have a UITableViewCell at the very bottom of tableview, it's functionality is to add new object to the list. But I also want the user to be able to move his objects. And here comes the problem I can not solve: how can I make this UITableViewCell not movable when tableView.isEditing is true so it is always at the bottom of section, even when user tries to move it there?
Here's a simple example of preventing rows from being moved past the last row:
class ReorderViewController: UITableViewController {
var myData = ["One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Don't let me move!"]
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(self.startEditing(_:)))
navigationItem.rightBarButtonItem = btn
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
#objc func startEditing(_ sender: Any) {
isEditing = !isEditing
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = myData[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// don't allow last row to move
return indexPath.row < (myData.count - 1)
}
override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
// if user tries to drop past last row
if proposedDestinationIndexPath.row == myData.count - 1 {
// send it back to original row
return sourceIndexPath
}
return proposedDestinationIndexPath
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let itemToMove = myData[sourceIndexPath.row]
myData.remove(at: sourceIndexPath.row)
myData.insert(itemToMove, at: destinationIndexPath.row)
}
}

tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) not getting called in UITableViewController subclass

numberOfSection and numberOfRowsInSection of UITableViewController is getting called but cellForRow not. What could be the reason ? Below is the code for tableViewController.
class GlobalSearchTableViewController: UITableViewController {
/// MARK: Properties
/// Delegate
weak var delegate: GlobalSearchTableViewControllerDelegate?
private var state = GlobalSearchTableState(searchResults: [])
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedSectionFooterHeight = 60
tableView.sectionFooterHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 60
tableView.rowHeight = UITableView.automaticDimension
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
extension GlobalSearchTableViewController: GlobalSearchTablePresenter {
func present(state: GlobalSearchTableState) {
tableView.reloadData()
}
try to return cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell : UITableViewCell!
cell = tableView.dequeueReusableCell(withIdentifier: "cell")
cell.textLabel?.text = dataArray[indexPath.row]
return cell
}
Try adding tableView.delegate = self or tableView.dataSource = self.

Make UItableview cell height equal to it's child UItableview

I have a UItableview cell that is contain a UItableview, I need to make height of that cell equal to height of it's child UItableview.
Image below explain what I need to do.
First see my ViewController,which has one tableview(tblview) and UITableViewCell(CustomTableViewCell) ,
class ViewController: UIViewController {
#IBOutlet var tblview:UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tblview.delegate = self
self.tblview.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.identifier) as! CustomTableViewCell
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
}
Then see my CustomTableViewCell which has one table view and one label in a cell.See,
class CustomTableViewCell: UITableViewCell {
static let identifier = "CustomTableViewCell"
#IBOutlet var tblviewCell:UITableView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.tblviewCell.delegate = self
self.tblviewCell.dataSource = self
tblviewCell.isScrollEnabled = false
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
let heighToReturn = self.tblviewCell.contentSize.height + 20 // upper and down space
return CGSize(width: self.tblviewCell.contentSize.width, height: heighToReturn)
}
}
extension CustomTableViewCell:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: customCell.identifier) as! customCell
cell.lblname?.text = "Vikas"
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
class customCell: UITableViewCell {
static let identifier = "customCell"
#IBOutlet weak var lblname :UILabel?
}
So, if you give tableview content size height in systemLayoutSizeFitting method then problem will be solve.
I hope this will help.
Here's how to do table header cells. The cell needs to be prototyped in the storyboard and subclassed (if needs to be configured). Then override the following funcs in the table view delegate. Alternatively, you can generate a view on the fly and return that from viewForHeaderInSection.
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 150
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCell(withIdentifier: "ConferenceHeaderCell") as! ConferenceDetailHeaderCell
// configure cell
return headerCell
}
For the cells themselves, it's very similar:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ConferenceUserCell", for: indexPath) as! ConferenceDetail_TVCell
// Configure the cell...
return cell
}
and depending, you may to implement 'heightForRowAtIndexPath'

how to set background color of the cells which are selected on section tableview

how to set background color of the cells which are selected on section tableview
every section or genre should have single selected cell only enter image description here
SEE Image description PLZ
I know how to select single cell in table view but here I wanted for every section only one select cell
this my code
var sections = [
Sections(genre: "🦁 Animation",
movies: ["The Lion King", "The Incredibles"],
expanded: false),
Sections(genre: "💥 Superhero",
movies: ["Guardians of the Galaxy", "The Flash", "The Avengers", "The Dark Knight"],
expanded: false),
Sections(genre:"👻 Horror",
movies: ["The Walking Dead", "Insidious", "Conjuring"],
expanded: false)
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].movies.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if(sections[indexPath.section].expanded){
return 44
}else{
return 0
}
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 2
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = ExpandableHeaderView()
header.customInit(title: sections[section].genre, section: section, delegate: self)
return header
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "labelCell")!
cell.textLabel?.text = sections[indexPath.section].movies[indexPath.row]
return cell
}
////////////
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, didHighlightRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
//let cell = tableView.dequeueReusableCell(withIdentifier: "labelCell")!
cell?.contentView.backgroundColor = UIColor.red
//cell?.backgroundColor = UIColor.red
}
func tableView(_ tableView: UITableView, didUnhighlightRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
//let cell = tableView.dequeueReusableCell(withIdentifier: "labelCell")!
cell?.contentView.backgroundColor = UIColor.white
//cell?.backgroundColor = UIColor.blue
}
////////////
func toggleSection(header: ExpandableHeaderView, section: Int) {
sections[section].expanded = !sections[section].expanded
tableView.beginUpdates()
for i in 0 ..< sections[section].movies.count{
tableView.reloadRows(at: [IndexPath(row: i , section: section)], with: .automatic)
}
tableView.endUpdates()
}
What you can do is a complete use of the delegate functions provided by the table view:
Inside func tableView(UITableView, didSelectRowAt: IndexPath) you can check the section and row that has been selected. You will also need to check a constant check on the var indexPathsForSelectedRows: [IndexPath]? array that this returns.
Now that you have a. the current selection b. the list of seelections,
you can go ahead and delete/add data into your final array as required.
So in your case, inside func tableView(UITableView, didSelectRowAt: IndexPath) you will check if the indexPathsForSelectedRows has the section+row count already. If it does, then simply play with the highlighting in the tableView: UITableView, didHighlightRowAt indexPath: IndexPath) and then change the array that stores the list of selected movies accordingly. If not simply add it.

Resources