【问题标题】:Fade edges of UITableViewUITableView 的淡入淡出边缘
【发布时间】:2012-05-21 03:57:48
【问题描述】:

我对我的问题进行了一些研究,但不幸的是,我的问题没有解决方案。 最接近的是Fade UIImageView as it approaches the edges of a UIScrollView,但它仍然不适合我。

我希望我的表格在顶部应用“隐形渐变”。如果单元格距离上边缘 50 像素,它就会开始消失。越靠近上边缘,零件越不可见。单元格高度约为 200 像素,因此单元格的下部需要 100% 可见。但没关系 - 我需要一个表格视图(或表格视图容器)来执行此任务,因为类似的表格可以显示其他单元格。

如果表格是纯色视图的子视图,我可以通过添加一个水平渐变的图像来实现,我可以将其延伸到任何宽度。该图像的顶部像素以背景的确切颜色开始,向下相同颜色具有较少的 alpha。

但是…… 我们有一个 透明颜色 的 UITableView。表格下方没有纯色,而是图案图像/纹理,在应用的其他屏幕上也可能不同。

你有什么想法我可以实现这种行为吗?

问候

【问题讨论】:

    标签: ios uitableview uiscrollview fade


    【解决方案1】:

    这是 Aviel Gross 对 Swift 的回答的翻译

    import UIKit
    
    class mViewController: UIViewController, UIScrollViewDelegate {
    
        //Emitted boilerplate code
    
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
    
            if self.tableView.layer.mask == nil {
    
                //If you are using auto layout
                //self.view.layoutIfNeeded()
    
                let maskLayer: CAGradientLayer = CAGradientLayer()
    
                maskLayer.locations = [0.0, 0.2, 0.8, 1.0]
                let width = self.tableView.frame.size.width
                let height = self.tableView.frame.size.height
                maskLayer.bounds = CGRect(x: 0.0, y: 0.0, width: width, height: height)
                maskLayer.anchorPoint = CGPoint.zero
    
                self.tableView.layer.mask = maskLayer
            }
    
            scrollViewDidScroll(self.tableView)
        }
    
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
    
            let outerColor = UIColor(white: 1.0, alpha: 0.0).cgColor
            let innerColor = UIColor(white: 1.0, alpha: 1.0).cgColor
    
            var colors = [CGColor]()
    
            if scrollView.contentOffset.y + scrollView.contentInset.top <= 0 {
                colors = [innerColor, innerColor, innerColor, outerColor]
            } else if scrollView.contentOffset.y + scrollView.frame.size.height >= scrollView.contentSize.height {
                colors = [outerColor, innerColor, innerColor, innerColor]
            } else {
                colors = [outerColor, innerColor, innerColor, outerColor]
            }
    
            if let mask = scrollView.layer.mask as? CAGradientLayer {
                mask.colors = colors
    
                CATransaction.begin()
                CATransaction.setDisableActions(true)
                mask.position = CGPoint(x: 0.0, y: scrollView.contentOffset.y)
                CATransaction.commit()
            }
    
        }
    
        //Emitted boilerplate code
    }
    

    【讨论】:

      【解决方案2】:

      @victorfigol 出色解决方案的 Swift 版本:

      class FadingTableView : UITableView {
        var percent = Float(0.05)
      
        private let outerColor = UIColor(white: 1.0, alpha: 0.0).cgColor
        private let innerColor = UIColor(white: 1.0, alpha: 1.0).cgColor
      
        override func awakeFromNib() {
          super.awakeFromNib()
          addObserver(self, forKeyPath: "bounds", options: NSKeyValueObservingOptions(rawValue: 0), context: nil)
        }
      
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
          if object is FadingTableView && keyPath == "bounds" {
              initMask()
          }
        }
      
        deinit {
          removeObserver(self, forKeyPath:"bounds")
        }
      
        override func layoutSubviews() {
          super.layoutSubviews()
          updateMask()
        }
      
        func initMask() {
          let maskLayer = CAGradientLayer()
          maskLayer.locations = [0.0, NSNumber(value: percent), NSNumber(value:1 - percent), 1.0]
          maskLayer.bounds = CGRect(x:0, y:0, width:frame.size.width, height:frame.size.height)
          maskLayer.anchorPoint = CGPoint.zero
          self.layer.mask = maskLayer
      
          updateMask()
        }
      
        func updateMask() {
          let scrollView : UIScrollView = self
      
          var colors = [CGColor]()
      
          if scrollView.contentOffset.y <= -scrollView.contentInset.top { // top
              colors = [innerColor, innerColor, innerColor, outerColor]
          }
          else if (scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height { // bottom
              colors = [outerColor, innerColor, innerColor, innerColor]
          }
          else {
              colors = [outerColor, innerColor, innerColor, outerColor]
          }
      
          if let mask = scrollView.layer.mask as? CAGradientLayer {
              mask.colors = colors
      
              CATransaction.begin()
              CATransaction.setDisableActions(true)
              mask.position = CGPoint(x: 0.0, y: scrollView.contentOffset.y)
              CATransaction.commit()
           }
        }
      }
      

      【讨论】:

      • 强制转换、分号、不使用类型推断、括号中的条件...请查看您的 Swift 3 副本。
      • 在展开可选层而不是强制它之后让它工作:如果让掩码 = scrollView.layer.mask as? CAGradientLayer { mask.colors = 颜色 }
      【解决方案3】:

      我拿了this的教程,做了一些修改和补充:

      • 它现在适用于所有表格视图 - 即使它们是更大屏幕的一部分。
      • 无论背景或 tableview 后面的任何内容如何,​​它都能正常工作。
      • 遮罩的变化取决于表格视图的位置 - 滚动到顶部时只有底部褪色,滚动到底部时只有顶部褪色...

      1.首先导入QuartzCore并在控制器中设置遮罩层

      编辑:不需要在课堂上引用CAGradientLayer

      #import <UIKit/UIKit.h>
      #import <QuartzCore/QuartzCore.h>
      
      @interface mViewController : UIViewController
      .
      .
      @end
      

      2. 将此添加到 viewWillAppear viewDidLayoutSubviews查看@Darren 对此的评论

      - (void)viewDidLayoutSubviews
      {
          [super viewDidLayoutSubviews];
      
          if (!self.tableView.layer.mask)
          {
              CAGradientLayer *maskLayer = [CAGradientLayer layer];
      
              maskLayer.locations = @[[NSNumber numberWithFloat:0.0], 
                                      [NSNumber numberWithFloat:0.2], 
                                      [NSNumber numberWithFloat:0.8], 
                                      [NSNumber numberWithFloat:1.0]];
      
              maskLayer.bounds = CGRectMake(0, 0,
                                  self.tableView.frame.size.width,
                                  self.tableView.frame.size.height);
              maskLayer.anchorPoint = CGPointZero;
      
             self.tableView.layer.mask = maskLayer;
          }
          [self scrollViewDidScroll:self.tableView];
      }
      

      3.通过将UIScrollViewDelegate 添加到控制器的.h 中,确保您是UIScrollViewDelegate 的代表:

      @interface mViewController : UIViewController <UIScrollViewDelegate>
      

      4.最后,在你的控制器.m中实现scrollViewDidScroll

      #pragma mark - Scroll View Delegate Methods
      
      - (void)scrollViewDidScroll:(UIScrollView *)scrollView
      {
          CGColorRef outerColor = [UIColor colorWithWhite:1.0 alpha:0.0].CGColor;
          CGColorRef innerColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
          NSArray *colors;
      
          if (scrollView.contentOffset.y + scrollView.contentInset.top <= 0) {
              //Top of scrollView
              colors = @[(__bridge id)innerColor, (__bridge id)innerColor,
                         (__bridge id)innerColor, (__bridge id)outerColor];
          } else if (scrollView.contentOffset.y + scrollView.frame.size.height
                     >= scrollView.contentSize.height) {
              //Bottom of tableView
              colors = @[(__bridge id)outerColor, (__bridge id)innerColor,
                         (__bridge id)innerColor, (__bridge id)innerColor];
          } else {
              //Middle
              colors = @[(__bridge id)outerColor, (__bridge id)innerColor,
                         (__bridge id)innerColor, (__bridge id)outerColor];
          }
          ((CAGradientLayer *)scrollView.layer.mask).colors = colors;
      
          [CATransaction begin];
          [CATransaction setDisableActions:YES];
          scrollView.layer.mask.position = CGPointMake(0, scrollView.contentOffset.y);
          [CATransaction commit];
      }
      

      再次重申:大部分解决方案来自this cocoanetics 教程。

      【讨论】:

      • 这很棒。但是,我会将掩码设置代码添加到viewDidLayoutSubviews 而不是viewWillAppear,因为根据大小,viewWillAppear 中没有完全定义布局(在我的 iPhone 6 上它缩小了 tableview)。
      • 是的...我写这篇文章的时候还没有今天那么重要,viewDidLayoutSubviews 确实是个更好的地方...
      • @Darren 如果我只希望它位于 UITableView 的底部,我是否应该更改滚动视图委托方法,是否应该更改 viewDidLayoutSubviews 方法?
      • 在 viewDidLayoutSubviews 中切换 numberWithFloat:0.2 到 0.0 应该可以解决问题
      • @Supertecnoboff viewDidLayoutSubviews 中的maskLayer.locations 的值与层大小相关,即现在淡入淡出是顶部20% 和底部20%。假设您只想在底部褪色 10%,然后将第三个值从 0.8 更改为 0.9
      【解决方案4】:

      这是我继承UITableView的淡化表格视图。已针对 iOS 7 和 8 进行测试。

      1. 不用实现scrollViewDidScroll,可以用layoutSubviews代替。
      2. 通过观察边界变化,掩码是 旋转变化时始终正确放置。
      3. 你可以使用百分比参数来改变你想要的边缘褪色程度,我 找到一个在某些情况下看起来更好的小值。

      CEFadingTableView.m

      #import "CEFadingTableView.h"
      
      @interface CEFadingTableView()
      
      @property (nonatomic) float percent; // 1 - 100%
      
      @end
      
      @implementation CEFadingTableView
      
      - (void)awakeFromNib
      {
          [super awakeFromNib];
      
          self.percent = 5.0f;
      
          [self addObserver:self forKeyPath:@"bounds" options:0 context:nil];
      }
      
      - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
      {
          if(object == self && [keyPath isEqualToString:@"bounds"])
          {
              [self initMask];
          }
      }
      
      - (void)dealloc
      {
          [self removeObserver:self forKeyPath:@"bounds"];
      }
      
      - (void)layoutSubviews
      {
          [super layoutSubviews];
      
          [self updateMask];
      }
      
      - (void)initMask
      {
          CAGradientLayer *maskLayer = [CAGradientLayer layer];
      
          maskLayer.locations = @[@(0.0f), @(_percent / 100), @(1 - _percent / 100), @(1.0f)];
      
          maskLayer.bounds = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
      
          maskLayer.anchorPoint = CGPointZero;
      
          self.layer.mask = maskLayer;
      
          [self updateMask];
      }
      
      - (void)updateMask
      {
          UIScrollView *scrollView = self;
      
          CGColorRef outer = [UIColor colorWithWhite:1.0 alpha:0.0].CGColor;
          CGColorRef inner = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
      
          NSArray *colors = @[(__bridge id)outer, (__bridge id)inner, (__bridge id)inner, (__bridge id)outer];
      
          if(scrollView.contentOffset.y <= 0) // top
          {
              colors = @[(__bridge id)inner, (__bridge id)inner, (__bridge id)inner, (__bridge id)outer];
          }
          else if((scrollView.contentOffset.y + scrollView.frame.size.height) >= scrollView.contentSize.height) // bottom
          {
              colors = @[(__bridge id)outer, (__bridge id)inner, (__bridge id)inner, (__bridge id)inner];
          }
      
          ((CAGradientLayer *)scrollView.layer.mask).colors = colors;
      
          [CATransaction begin];
          [CATransaction setDisableActions:YES];
          scrollView.layer.mask.position = CGPointMake(0, scrollView.contentOffset.y);
          [CATransaction commit];
      }
      
      @end
      

      【讨论】:

      • 知道如何仅在 tableView 的底部实现这样的功能吗?
      • 在这两个和@Aviel Gross 的解决方案中,每次更新掩码时都会重新初始化颜色和渐变值。诚然,这不是一项庞大的工作,但它是不必要的,而且在节省设备电池电量时,每一点都很重要。我会将这些值存储在实例变量中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多