Juanpe / SkeletonView

☠️ An elegant way to show users that something is happening and also prepare them to which contents they are awaiting
MIT License
12.62k stars 1.12k forks source link

Does not work in all table cells #541

Open NikTsvTks opened 1 year ago

NikTsvTks commented 1 year ago

Description

Describe your issue here.

What type of issue is this? (place an x in one of the [ ])

Requirements (place an x in each of the [ ])


Bug Report

I have tableView with different cell in different sections Simulator Screen Shot - iPhone 14 Pro Max - 2023-06-16 at 20 27 05

I need create skeletonView like that

Снимок экрана 2023-06-16 в 20 26 19

But when i use skeletonView on this screen, i get this result Simulator Screen Shot - iPhone 14 Pro Max - 2023-06-16 at 20 27 03

Steps to reproduce:

Please replace this with the steps to reproduce the behavior.

I add dataForUI for skeleton and after create table

override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.prepareDataForSkeleton()
        setUpViews()
}

 fileprivate func setUpViews() {
        view.addSubview(headerTitle)
        headerTitle.labelTitle.text = "Оформление заказа"
        headerTitle.snp.makeConstraints { (make) in
            make.top.equalTo(0).offset(Utils.shared.screenHeight > 800 ? 60 : 20)
            make.left.equalTo(0)
            make.right.equalTo(0)
        }
        headerTitle.layoutIfNeeded()
        viewModel.model.titleHeight = Float(headerTitle.labelTitle.frame.height)

        view.isSkeletonable = true

        view.addSubview(table)
        table.delegate = self
        table.dataSource = self
        table.alwaysBounceVertical = true
        table.isScrollEnabled = true
        table.contentInsetAdjustmentBehavior = .never
        table.estimatedRowHeight = 0
        table.rowHeight = UITableView.automaticDimension
        table.snp.makeConstraints { (make) in
            make.top.equalTo(headerTitle.snp.bottom).offset(-5)
            make.bottom.equalTo(0)
            make.left.equalTo(0)
            make.right.equalTo(0)
        }
        table.layoutIfNeeded()
}

Code in cell

class OrderAddressTableViewCell: BaseTableViewCell {
    public var onTap: (() -> Void)?

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.action(_:))))
        setUpViews()
        contentView.isSkeletonable = true
        isSkeletonable = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    fileprivate let titleLabel: BaseLabel = {
        let label = BaseLabel()
        label.font = Utils.shared.getFont(Utils.shared.adaptive(16), .bold, .proxima)
        label.textColor = Utils.shared.getColor(.black)
        label.text = "Адрес и способ доставки"
        label.isHidden = true
        return label
    }()

    fileprivate let addressLabel: BaseLabel = {
        let label = BaseLabel()
        label.font = Utils.shared.getFont(Utils.shared.adaptive(13), .regular, .proxima)
        label.textColor = Utils.shared.getColor(.black)
        label.letterSpacing = 0.24
        label.numberOfLines = 2
        label.lineBreakMode = .byWordWrapping
        label.lineSpacing = 4
        return label
    }()

    fileprivate let typeDeliveryLabel: BaseLabel = {
        let label = BaseLabel()
        label.font = Utils.shared.getFont(Utils.shared.adaptive(13), .regular, .proxima)
        label.textColor = Utils.shared.getColor(.black)
        label.letterSpacing = 0.24
        label.numberOfLines = 1
        label.lineBreakMode = .byWordWrapping
        label.lineSpacing = 4
        return label
    }()

    // MARK: imageViewChevrone

    fileprivate var imageViewChevrone: BaseImageView = {
        let imageView = BaseImageView()
        imageView.image = R.image.category_chevrone()
        return imageView
    }()

    public var skeletonAddressView: BaseView = {
        let view = BaseView()
        view.isSkeletonable = true
        return view
    }()
}

extension OrderAddressTableViewCell {
    fileprivate func setUpViews() {

        contentView.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.top.equalTo(0)
            make.left.equalTo(16)
            make.right.equalTo(-16)
        }

        contentView.addSubview(addressLabel)
        addressLabel.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(4)
            make.left.equalTo(16)
            make.right.equalTo(-32)
        }

        contentView.addSubview(typeDeliveryLabel)
        typeDeliveryLabel.snp.makeConstraints { make in
            make.top.equalTo(addressLabel.snp.bottom).offset(4)
            make.left.equalTo(16)
            make.right.equalTo(-16)
            make.bottom.equalTo(-11)
        }

        contentView.addSubview(imageViewChevrone)
        imageViewChevrone.snp.makeConstraints { (make) in
            make.centerY.equalTo(contentView.snp.centerY)
            make.height.equalTo(16)
            make.width.equalTo(16)
            make.right.equalTo(-16)
        }

        contentView.addSubview(skeletonAddressView)
        skeletonAddressView.snp.makeConstraints { make in
            make.left.equalTo(16)
            make.right.equalTo(-16)
            make.top.bottom.equalTo(0)
        }
    }

    public func initialize(address: String, deliveryType: String) {
        addressLabel.text = address
        typeDeliveryLabel.text = deliveryType
        contentView.hideSkeleton()
        hideSkeleton()
        titleLabel.isHidden = false
    }

    public func initializeWithSkeleton() {
        let gradient = SkeletonGradient(baseColor: Utils.shared.getColor(.hF9F9F9), secondaryColor: .white)
        let animation = SkeletonAnimationBuilder().makeSlidingAnimation(withDirection: .leftRight)
        skeletonAddressView.showAnimatedGradientSkeleton(usingGradient: gradient, animation: animation)
    }
}

And the same code in every cell, but when I call initializeWithSkeleton in every cell, I have skeleton for only one cell, but if I commented "initializeWithSkeleton" for all cell and leave for one, I have skeleton in this cell

In other screen It's working fine, but on this screen doesn't. I don't why, any help me, pls?

SkeletonView Environment:

SkeletonView version: 1.30.4 Xcode version: Version 14.2 (14C18) Swift version: Swift version 5.7.2

Alesh14 commented 1 year ago
func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -> UITableViewCell? {
    let cell = tableView.dequeueReusableCell(withIdentifier: K.surahIdentifier) as? SurahNameCell

    guard let cell = cell else { return UITableViewCell() }

    cell.someView.isSkeletonable = true
    cell.someView.showAnimatedGradientSkeleton()

    return cell
}

try this method with SkeletonTableViewDataSource protocol

NikTsvTks commented 1 year ago
func collectionSkeletonView(_ skeletonView: UITableView, skeletonCellForRowAt indexPath: IndexPath) -> UITableViewCell? {
    let cell = tableView.dequeueReusableCell(withIdentifier: K.surahIdentifier) as? SurahNameCell

    guard let cell = cell else { return UITableViewCell() }

    cell.someView.isSkeletonable = true
    cell.someView.showAnimatedGradientSkeleton()

    return cell
}

попробуйте этот метод с протоколом SkeletonTableViewDataSource

Sorry, but it didn't help me

NikTsvTks commented 1 year ago

https://github.com/Juanpe/SkeletonView/assets/67915638/a043e3b4-2e9b-4973-99f3-ac32b2d1f97c

I have this result. I don't use hideSkeleton() after finished load.

I use skeleton for special view in cell, in all cell on this screen and painted them so you can see what they are. They are red and green color. When I open screen in first time, I see only one skeleton, but if don't hide skeleton after load, we see other skeleton and if exit from screen and back again we see normal work skeleton. How fix it, can you help me? I hope I wrote clearly

Alesh14 commented 1 year ago

Брат, я прочитал твой текст и посмотрел видео которое ты скинул и ничего не понял. Объясни на русском)

NikTsvTks commented 1 year ago

https://github.com/Juanpe/SkeletonView/assets/67915638/618b5d72-5f2d-4efd-93c2-16ce024538de

В общем, проблема такая. Чтобы сделать скелетон, я делаю отдельную модель для таблицы именно для скелетона. После загрузки всей инфы я перезагружаю таблицу использую уже нормальную модель и загружается все остальная информация. На главном экране все работает ок. Если открыть экран с оформлением заказа, то скелетон показывается только для первой ячейки (уточнение: в каждой ячейке я использую отдельно сделанный view специально для скелетона, я их раскрасил еще, чтобы проверить, что они точно есть). И после загрузки всей инфы, показываются остальные скелетоны (хотя должны были быть сразу). НО если перезайти на этот экран, то будет работать нормально, если перезайти еще раз, то еще лучше (на втором видео)

Alesh14 commented 1 year ago

а ты попробовал временно удалить Skeleton? вдруг Skeleton тут не причем

NikTsvTks commented 1 year ago

Да, без скелетона норм. Тут же проблема в том, что в остальных ячейках не показывается скелетон, а только в одной. Если я закомментирую скелетоны во всех ячейках кроме одной, то в этой будет показываться, а если включить все обратно, то только в одной

tvoyfm commented 1 year ago

When running multiple loaders simultaneously, make sure they are all called on the main thread. I had this bug, but after wrapping it in the main thread the problem disappeared

DispatchQueue.main.async { view.showAnimatedGradientSkeleton() }

@Juanpe, a call to view.showAnimatedGradientSkeleton() guarantee that the animation will run on the main thread?

Reference of the answer: https://github.com/Juanpe/SkeletonView/issues/164#issuecomment-543625071