SwiftUI列表中的自定义按钮

时间:2020-04-02 15:32:36

标签: swift list button swiftui

SwiftUI Custom Button in List

我正在尝试在SwiftUI列表中创建自定义按钮。我希望它具有蓝色和白色文本背景,重要的是要保持蓝色并在按下时达到50%的不透明度,而不是默认的灰色。

我尝试使用自定义的ButtonStyle,但是当我这样做时,按钮的可点击区域被缩小为仅标签本身。如果我点击单元格的任何其他部分,颜色不会改变。如果我删除ButtonStyle,则在单元格上的任意位置轻按即可

如何解决此问题,以便获得自定义颜色,包括点击时的颜色,但整个单元仍可轻敲?

import SwiftUI

struct BlueButtonStyle: ButtonStyle {

  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
        .font(.headline)
        .foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color.white)
        .listRowBackground(configuration.isPressed ? Color.blue.opacity(0.5) : Color.blue)
  }
}

struct ExampleView: View {

    var body: some View {
        NavigationView {
            List {
                Section {
                    Text("Info")
                }

                Section {
                    Button(action: {print("pressed")})
                    {
                        HStack {
                            Spacer()
                            Text("Save")
                            Spacer()
                        }

                    }.buttonStyle(BlueButtonStyle())
                }
            }
            .listStyle(GroupedListStyle())
            .environment(\.horizontalSizeClass, .regular)
            .navigationBarTitle(Text("Title"))
        }
    }
}

struct ExampleView_Previews: PreviewProvider {
    static var previews: some View {
        ExampleView()
    }
}

1 个答案:

答案 0 :(得分:7)

在标准变体列表中,List会拦截并处理轻敲检测的内容区域,在您的自定义样式中,默认情况下,它是由不透明区域定义的,不透明区域只是您的情况下的文本,因此更正的样式是

通过Xcode 11.4 / iOS 13.4测试

demo

public class RelayAsyncCommand<T> : RelayCommand<T>
{
    private bool _isExecuting = false;

    public event EventHandler Started;

    public event EventHandler Ended;

    public bool IsExecuting
    {
        get { return _isExecuting; }
        private set
        {
            if (value != _isExecuting)
            {
                _isExecuting = value;
                CommandManager.InvalidateRequerySuggested();
            }
        }
    }

    public RelayAsyncCommand(Action<T> execute, Predicate<T> canExecute)
        : base(execute, canExecute)
    {
    }

    public RelayAsyncCommand(Action<T> execute)
        : base(execute)
    {
    }

    public override bool CanExecute(object parameter)
    {
        return ((base.CanExecute(parameter)) && (!IsExecuting));
    }

    public override void Execute(object parameter)
    {
        try
        {
            IsExecuting = true;
            Started?.Invoke(this, EventArgs.Empty);

            Task task = Task.Factory.StartNew(() =>
            {
                _execute((T)parameter);
            });

            task.ContinueWith(t =>
            {
                OnRunWorkerCompleted(EventArgs.Empty);
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
        catch (Exception ex)
        {
            OnRunWorkerCompleted(new RunWorkerCompletedEventArgs(null, ex, true));
        }
    }

    private void OnRunWorkerCompleted(EventArgs e)
    {
        IsExecuting = false;
        Ended?.Invoke(this, e);
    }
}

和用法,仅

struct BlueButtonStyle: ButtonStyle {

  func makeBody(configuration: Self.Configuration) -> some View {
    configuration.label
        .font(.headline)
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
        .contentShape(Rectangle())
        .foregroundColor(configuration.isPressed ? Color.white.opacity(0.5) : Color.white)
        .listRowBackground(configuration.isPressed ? Color.blue.opacity(0.5) : Color.blue)
  }
}

甚至

Button(action: {print("pressed")})
{
    Text("Save")
}.buttonStyle(BlueButtonStyle())