Хорошо, у меня есть способ сделать это в ванили JavaScript - Демонстрация: https://codepen.io/Alexander9111/pen/povqpaG
Я никогда раньше не использовал React Native, поэтому не могу дать Вы точный код для этого, но я полагаю, что концепция является наиболее важной вещью?
Мой HTML выглядит так:
<button id="forwards">Forwards</button>
<button id="backwards">Backwards</button>
<Svg height="280" width="400">
<Path id="target" d="M0 0 V200 C0 200, 400 400, 0400, 120 V0 " fill="#85ffda" stroke="#85ffda"/>
<g transform="translate(0,00)">
<path d="M0 0 V200 Q 395 370 400 120 V0 Z" stroke-width="1" stroke="black" fill="transparent"/>
<path d="M0 0 V200 Q 300 300 400 150 V0 Z" stroke="black" fill="transparent"/>
<path d="M0 0 V200 Q 250 250 400 175 V0 Z" stroke="black" fill="transparent"/>
<path d="M0 0 V200 Q 250 200 400 200 V0 Z" stroke="black" fill="transparent"/>
</g>
</svg>
И JavaScript вот так:
// d= { numInputTouched? "M0 0 V200 C0 200, 400 400, 0" + WIDTH + ", 120 V0 ":"M0 0 V200 H" + WIDTH + ", V0"}
// //"M0 0 V200 H" + WIDTH + ", V0"
// // d={"M0 0 V200 C0 200, 400 400, 0" + WIDTH + ", 120 V0"}
const WIDTH = 400;
const svg = document.querySelector("svg");
svg.setAttribute('width', WIDTH);
const before = ['M', [0,0], 'V', [200], 'Q', [395, 370], ' ', [WIDTH, 120], 'V', [0], 'Z'];
const after = ['M', [0,0], 'V', [200], 'Q', [180, 200], ' ', [WIDTH, 200], 'V', [0], 'Z'];
const diff = ['M', [0,0], 'V', [0], 'Q', [-145, -170], ' ', [0, 80], 'V', [0], 'Z'];
console.log(before.join(' '))
// const target = document.getElementById("target");
// target.setAttribute('d', "M0 0 V200 H" + WIDTH + ", V0");
// target.setAttribute('d', "M0 0 V200 C0 200, 400 400, 0" + WIDTH + ", 120 V0 ");
target.setAttribute('d', before.join(' '));
var current = ['M', [0,0], 'V', [200], 'Q', [395, 370], ' ', [400, 120], 'V', [0], 'Z'];
function transition(i) {
current[1][0] = before[1][0] + Math.round((i/100)*diff[1][0],0);
current[1][1] = before[1][1] + Math.round((i/100)*diff[1][1],0);
current[3][0] = before[3][0] + Math.round((i/100)*diff[3][0],0);
current[5][0] = before[5][0] + Math.round((i/100)*diff[5][0],0);
current[5][1] = before[5][1] + Math.round((i/100)*diff[5][1],0);
current[7][0] = before[7][0] + Math.round((i/100)*diff[7][0],0);
current[7][1] = before[7][1] + Math.round((i/100)*diff[7][1],0);
target.setAttribute('d', current.join(' '));
}
console.log(current.join(' '));
var progress = 0;
var timeInterval; //to be started at a later time
function myTimerForward() {
console.log(progress);
if (progress == 100) {
clearInterval(timeInterval);
} else {
progress += 1;
transition(progress);
}
}
function myTimerBackward() {
console.log(progress);
if (progress == 0) {
clearInterval(timeInterval);
} else {
progress -= 1;
transition(progress);
}
}
document.querySelector("#forwards").addEventListener('click', function() {
timeInterval = setInterval(myTimerForward, 10);
});
document.querySelector("#backwards").addEventListener('click', function() {
timeInterval = setInterval(myTimerBackward, 10);
});
Итак, я немного изменил форму пути svg, чтобы сделать ее более простой (но такой же формы) - я использовал более простую версию кривой Безье, квадратичную c one - https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths#Bezier_Curves
Другой тип кривой Безье, квадратичная c кривая, называемая Q, на самом деле является более простой кривой, чем cubi c one
Тогда это позволяет мне описать кривую довольно просто с помощью массива:
const before = ['M', [0,0], 'V', [200], 'Q', [395, 370], ' ', [WIDTH, 120], 'V', [0], 'Z'];
, который с течением времени переходит к:
const after = ['M', [0,0], 'V', [200], 'Q', [180, 200], ' ', [WIDTH, 200], 'V', [0], 'Z'];
Разница между ними такова:
const diff = ['M', [0,0], 'V', [0], 'Q', [-145, -170], ' ', [0, 80], 'V', [0], 'Z'];
Это означает, что я могу взять часть этой разницы и добавить ее до, и мы будем медленно двигаться к желаемому конечному результату (af ter).
Остальное - просто установить setInterval для запуска функции каждые 10 миллисекунд для медленного перехода формы к конечному результату. Я не уверен, что вы бы использовали тот же setInterval et c. в ReactNative?
Это приводит к перемещению между изогнутым и плоским при нажатии кнопки «вперед» и между плоским и изогнутым при нажатии кнопки «назад». В вашем примере вы вместо этого запускаете связанные функции для какого-либо события onFocus et c.?
Пример:
(Примечание: черные линии - это просто пути, и есть только рекомендации, показывающие, как происходит этот переход)
ОБНОВЛЕНИЕ С ИСПОЛЬЗОВАНИЕМ SMIL
Существует также возможность использовать SMIL (язык синхронизации синхронизированных мультимедиа - http://www.w3.org/TR/REC-smil) - я не уверен на 100%, работает ли это в React-native, но я бы предположил, что так.
Демонстрация: https://codepen.io/Alexander9111/pen/MWYRzNp
Тогда мы можем упростить наш код. Нам просто нужно сначала добавить один тег animate element к нашему HTML, который описывает анимацию:
<Svg height="400" width="400">
<Path id="target" d="M0 0 V200 Q 395 370 400 120 V0 Z" fill="#85ffda" stroke="#85ffda">
<animate
attributeName="d"
from="M0 0 V200 Q 395 370 400 120 V0 Z"
to="M0 0 V200 Q 180 200 400 200 V0 Z"
dur="0.5s" repeatCount="1" begin="indefinite" fill="freeze" />
</path>
...
</svg>
А затем JavaScript просто так:
const target = document.querySelector("#target");
const animate_el = document.querySelector("#target > animate");
const from = animate_el.getAttribute("from");
const to = animate_el.getAttribute("to");
var d;
function forwards(){
d = target.getAttribute("d");
animate_el.setAttribute("from", d);
animate_el.setAttribute("to", to);
animate_el.beginElement();
}
function backwards(){
d = target.getAttribute("d");
animate_el.setAttribute("from", d);
animate_el.setAttribute("to", from);
animate_el.beginElement();
}
document.querySelector("#forwards").addEventListener('click', forwards);
document.querySelector("#backwards").addEventListener('click', backwards);
document.querySelector("#input_div > input").addEventListener('focus', forwards);
document.querySelector("#input_div > input").addEventListener('blur', backwards);
Мы действительно нужно только захватить атрибуты from="..."
и to="..."
, чтобы мы могли перевернуть их при движении в обратном направлении, а также захватить текущий атрибут d="..."
пути. Это необходимо, если мы начнем переход до того, как закончится другой, чтобы гарантировать, что мы не получим скачкообразную анимацию, перезапускающую свою позицию и т. Д. c. Затем, наконец, просто прикрепите эти функции к событиям щелчка / фокуса ввода / кнопок, и все готово!