设备旋转后如何重新计算约束

时间:2019-04-01 21:14:58

标签: ios swift uitableview uistackview

在表格视图的单元格中,我具有包含视图的堆栈视图。我跟踪堆栈视图的约束。我根据堆栈视图中要显示的视图数量来计算此尾随约束的值。

在设备旋转后,有什么方法可以重新计算该尾随约束值并显示视图,而无需在viewWillTransition中重新加载表视图吗?

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    self.tableView.reloadData()

    // self.view.layoutIfNeeded() // This doesn't recalculate constraints
}

Storyboard

layoutIfNeeded

2 个答案:

答案 0 :(得分:1)

您可以通过几种方法进行此操作-轮换(或更改尺寸)时重新计算尺寸可能不是最佳方法。

一种利用from django.contrib.admin import widgets from django.utils.http import urlencode class AutocompleteSelect(widgets.AutocompleteSelect): """ Improved version of django's autocomplete select that sends an extra query parameter with the model and field name it is editing, allowing the search function to apply the appropriate filter. Also wider by default, and adds a debounce to the ajax requests """ def __init__(self, rel, admin_site, attrs=None, choices=(), using=None, for_field=None): super().__init__(rel, admin_site, attrs=attrs, choices=choices, using=using) self.for_field = for_field def build_attrs(self, base_attrs, extra_attrs=None): attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs) attrs.update({ 'data-ajax--delay': 250, 'style': 'width: 50em;' }) return attrs def get_url(self): url = super().get_url() url += '?' + urlencode({ 'app_label': self.for_field.model._meta.app_label, 'model_name': self.for_field.model._meta.model_name, 'field_name': self.for_field.name }) return url class UseAutocompleteSelectMixin: """ To avoid ForeignKey fields to Event (such as on ReportColumn) in admin from pre-loading all events and thus being really slow, we turn them into autocomplete fields which load the events based on search text via an ajax call that goes through this method. Problem is this ignores the limit_choices_to of the original field as this ajax is a general 'search events' without knowing the context of what field it is populating. Someone else has exact same problem: https://stackoverflow.com/questions/55344987/how-to-filter-modeladmin-autocomplete-fields-results-with-the-context-of-limit-c So fix this by adding extra query parameters on the autocomplete request, and use these on the target ModelAdmin to lookup the correct limit_choices_to and filter with it. """ # Overrides django.contrib.admin.options.BaseModelAdmin#formfield_for_foreignkey # Is identical except in case db_field.name is in autocomplete fields it constructs our improved AutocompleteSelect # instead of django's and passes it extra for_field parameter def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name in self.get_autocomplete_fields(request): db = kwargs.get('using') kwargs['widget'] = AutocompleteSelect(db_field.remote_field, self.admin_site, using=db, for_field=db_field) if 'queryset' not in kwargs: queryset = self.get_field_queryset(db, db_field, request) if queryset is not None: kwargs['queryset'] = queryset return db_field.formfield(**kwargs) return super().formfield_for_foreignkey(db_field, request, **kwargs) # In principle we could add this override in a different mixin as adding the formfield override above is needed on # the source ModelAdmin, and this is needed on the target ModelAdmin, but there's do damage adding everywhere so combine them. def get_search_results(self, request, queryset, search_term): if 'app_label' in request.GET and 'model_name' in request.GET and 'field_name' in request.GET: from django.apps import apps model_class = apps.get_model(request.GET['app_label'], request.GET['model_name']) limit_choices_to = model_class._meta.get_field(request.GET['field_name']).get_limit_choices_to() if limit_choices_to: queryset = queryset.filter(**limit_choices_to) return super().get_search_results(request, queryset, search_term) search_fields = ['translations__name'] 处理所有布局的方法是在堆栈视图中添加“空白”视图。如果您仅设置要显示的1或2个“实际”视图,则还可以显示“空白”视图以填写 3个“列”。

因此,假设您可能会显示零实际视图的行,则将原型保持原样,但是然后:

  • 向堆栈视图添加IBOutlet引用
  • UIStackView中,创建3个清晰的awakeFromNib()并将其添加到堆栈视图中
  • 跟踪阵列中的实际视图和空白视图

现在,当您设置要显示的视图时, 隐藏 视图将显示为 not 显示 足够的空白视图以保持3个视图可见。

示例:

  • UIView隐藏[1, 2]并显示view3
  • blank1隐藏[2]view1并显示view3blank1

因此,您的堆栈中将始终有3个子视图,并且无需进行任何计算...自动布局将使它们保持排列状态。

这是一个示例实现:

blank2

产生肖像:

和风景:


编辑:

这是另一个示例,使用具有class ThreeColCell: UITableViewCell { @IBOutlet var mainStackView: UIStackView! @IBOutlet var view1: UIView! @IBOutlet var view2: UIView! @IBOutlet var view3: UIView! var arrayOfRealViews: [UIView] = [UIView]() var arrayOfBlankViews: [UIView] = [UIView]() var myData: [Int] = [Int]() { didSet { // hide all the views in the stack mainStackView.arrangedSubviews.forEach { $0.isHidden = true } // show the specified "real" views myData.forEach { i in arrayOfRealViews[i - 1].isHidden = false } // if fewer than 3 "real" views, show "blank" view(s) for i in 0..<(3 - myData.count) { arrayOfBlankViews[i].isHidden = false } } } override func awakeFromNib() { super.awakeFromNib() commonInit() } func commonInit() -> Void { // ordered array of views 1 to 3 arrayOfRealViews = [view1, view2, view3] // add 3 "blank" views to the stack view // and to array of blank views for _ in 0..<3 { let v = UIView() v.translatesAutoresizingMaskIntoConstraints = false v.backgroundColor = .clear mainStackView.addArrangedSubview(v) arrayOfBlankViews.append(v) } } } class ThreeColTableViewController: UITableViewController { var theData = [ [1, 2], [1, 2, 3], [1], [1, 2, 3], [2], [2, 3], [1, 2, 3], [3], [2, 3], [1, 2, 3], ] override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return theData.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ThreeColCell", for: indexPath) as! ThreeColCell cell.myData = theData[indexPath.row] return cell } } (以及2和3)属性的结构数组:

.isDisabled1

答案 1 :(得分:0)

您应该实现该方法

func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)

当设备转换到新视图(横向或纵向)时会调用哪个。在这种情况下,您可以更改约束并致电

view.setNeedsLayout()  为了标记该布局,需要在下一个Runloop中重新计算。