Перед тем, как начать, рассмотрите возможность подписки по этой ссылке, и если вы не читаете ее на TrailingClosure.com, приходите к нам как-нибудь!
Начиная
В приведенном выше примере я показал, как это выглядит, когда Rectangle
используется в качестве маски для эффекта растворения. Однако в этом уроке мы собираемся создать ViewModifier
, который принимает любую View
в качестве формы, которую он использует для создания эффекта растворения. Следите за обновлениями, чтобы увидеть, насколько силен этот эффект на самом деле!
- Создайте новый
ViewModifier
с именемShapeDissolveModifier
. Ниже приведен шаблон для нашей структуры. Определены две переменные. Первый - это нашmask
для эффекта растворения. Наш типMask
определен выше как общий наShapeDissolveModifier
. Второй - этоprogress
анимации растворения. По мере увеличения с0
до1
вид будет растворяться.
struct ShapeDissolveModifier<Mask: View>: ViewModifier {
let mask: Mask
var progress: Double
func body(content: Content) -> some View {
content
}
}
- Создайте новую функцию
buildMask(GeometryProxy, Double) -> some View
. Задача этой функции - взять шаблон маски, который мы определили ранее,mask
, и создать 100 копий различныхopacity
. Эти копии объединяются, образуя полную маску, которая со временем растворяется.
func buildMask(geometry: GeometryProxy, progress: Double) -> some View {
// Create Dissolve Mask here...
}
- Внутри функции мы используем
GeometryProxy
для вычисления размера копий части маски.
func buildMask(geometry: GeometryProxy, progress: Double) -> some View {
let width = geometry.size.width
let height = geometry.size.height
let wUnit = width/10.0
let hUnit = height/10.0
// resize the mask to 1/10th of the parent view.
let maskPiece = mask
.frame(width: wUnit, height: hUnit, alignment: .center)
}
- Затем нам нужно создать три закрытия, чтобы мы могли сгенерировать значения
x
,y
иopacity
для копий маски.
func buildMask(geometry: GeometryProxy, progress: Double) -> some View {
let width = geometry.size.width
let height = geometry.size.height
let wUnit = width/10.0
let hUnit = height/10.0
// resize the mask to 1/10th of the parent view.
let maskPiece = mask
.frame(width: wUnit, height: hUnit, alignment: .center)
// Calculate X coordinate for a mask copy
let xCoord = { (x:Int) -> CGFloat in
wUnit * CGFloat(x)
}
// Calculate Y coordinate for a mask copy
let yCoord = { (y:Int) -> CGFloat in
hUnit * CGFloat(y)
}
// Calculate a random opacity for a mask copy
let opacity = { () -> Double in
return Double.random(in: 0...3) * progress + progress
}
}
- Теперь соберем их все вместе. Мы будем использовать
ForEach
для создания100
mask
частей с соответствующими значениями, используя только что сделанные замыкания.
func buildMask(geometry: GeometryProxy, progress: Double) -> some View {
let width = geometry.size.width
let height = geometry.size.height
let wUnit = width/10.0
let hUnit = height/10.0
// resize the mask to 1/10th of the parent view.
let maskPiece = mask
.frame(width: wUnit, height: hUnit, alignment: .center)
// Calculate X Coordinate for a mask copy
let xCoord = { (x:Int) -> CGFloat in
wUnit * CGFloat(x)
}
// Calculate Y Coordinate for a mask copy
let yCoord = { (y:Int) -> CGFloat in
hUnit * CGFloat(y)
}
// Calculate Random Opacity for a mask copy
let opacity = { () -> Double in
return Double.random(in: 0...3) * progress + progress
}
// Combine all of the mask pieces together
let fullMask = Group {
ForEach(0..<100) { x in
maskPiece
.offset(x: xCoord(x%10), y: yCoord(x/10))
.opacity(opacity())
}
}
return fullMask
}
Примеры использования!
А теперь самое интересное. Я собрал несколько разных примеров. В основном я просто играю с ним, но вы сможете увидеть некоторые изящные способы использования.
Это разные эффекты, основанные на простом изменении mask
, передаваемого в ShapeDissolveModifier
.
Rectangle()
.foregroundColor(.blue)
.frame(width: 300, height: 300, alignment: .center)
.cornerRadius(10)
.modifier(ShapeDissolveModifier(mask:
Rectangle()
,progress: progress))
.onAppear {
withAnimation(Animation.easeInOut(duration: 3.0)) {
self.progress = 1.0
}
}
Rectangle()
.scaleEffect(0.9)
Используйте это на изображениях
Image("mountains")
.resizable()
.scaledToFill()
.foregroundColor(.blue)
.frame(width: 300, height: 300, alignment: .center)
.cornerRadius(10)
.modifier(ShapeDissolveModifier(mask:
Rectangle()
,progress: progress))
.onAppear {
withAnimation(Animation.easeInOut(duration: 3.0)) {
self.progress = 1.0
}
}
Triangle()
.rotation(Angle(degrees: 90))
.scaleEffect(3)
Circle()
.scaleEffect(1.5)
Поддержите будущие учебники, подобные этому!
Пожалуйста, рассмотрите возможность подписки по этой ссылке. Если вы не читаете это на TrailingClosure.com, приходите к нам как-нибудь!
Мы хотим увидеть твои работы! Если вы что-то построили с помощью этого урока, присылайте нам фотографии! Найдите нас в Twitter @TrailingClosure или напишите нам по адресу [email protected]