[prg] Обработка клика в костомном view в android
Всех приветствую. В telegramm под android есть проблема,т.е в android 7
и раньше незрячим невозможно отвечать или отклонять звонки,т.е двойной
таб по view не работает. Поскольку техподдержка не отреагировала на мою
проблему,я решил самостоятельно собрать официальный telegramm под
android,чтобы попытаться исправить эту проблему,и у меня это вроде
получилось. Но прежде чем заливать это на github и отправлять pull
request,я хочу проконсультироваться с более опытными разработчиками под
android,как более правильно обрабатывать клик по костомному view,чтобы
это работало на всех андроидах. Я делал только модификацию костомного
view CallSwipeView.java.
1. У меня почему-то не отрабатывает action click в методе
PerformAccessibilityAction,когда перед этим при вызове метода
onInitializeAccessibilityNodeInfo добавляется action click. Поэтому я в
конструкторе использовал метод setClickable true и переопределил метод
performClick,или вместо переопределения этого метода мне лучше
переопределить метод onPopulateAccessibilityEvent и проверять тип
события на clicked?
2. в ontouchEvent я вместо переменной
dragging возвращаю super.onTouchEvent,т.к без этого клик тоже не
отрабатывается. Но в этом случае,возможно,утрачивается
функциональность,которая была написана для зрячих? Метод,который
позволяет принять/отклонить звонок и который должен вызваться при
двойном тапе по view - listener.onDragComplete(). Как мне стоит
поступить в этих двух случаях,чтобы увеличить вероятность того,что
разработчики telegramm примут мой pull request? Далее будет код
костомного view,чтобы людям не нужно было заходить в исходники telegramm
и искать этот класс. Заранее всем огромное спасибо за помощь. package
org.telegram.ui.Components.voip;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.BuildVars;
import org.telegram.messenger.FileLog;
import java.util.ArrayList;
public class CallSwipeViewextends View {
private PaintarrowsPaint,pullBgPaint;
private int[]arrowAlphas = {64,64,64};
private ViewviewToDrag;
private boolean dragging =false,dragFromRight;
private float dragStartX;
private RectFtmpRect =new RectF();
private Listenerlistener;
private Patharrow =new Path();
private AnimatorSetarrowAnim;
private boolean animatingArrows =false;
private boolean canceled =false;
public CallSwipeView(Context context) {
super(context);
init();
}
private void init() {
//Эта строка добавлена мной.
setClickable(true);
arrowsPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
arrowsPaint.setColor(0xFFFFFFFF);
arrowsPaint.setStyle(Paint.Style.STROKE);
arrowsPaint.setStrokeWidth(AndroidUtilities.dp(2.5f));
pullBgPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
ArrayList<Animator> anims =new ArrayList<>();
for (int i =0; i <arrowAlphas.length; i++) {
ArrowAnimWrapper aaw =new ArrowAnimWrapper(i);
ObjectAnimator anim =
ObjectAnimator.ofInt(aaw,"arrowAlpha",64,255,64);
anim.setDuration(700);
anim.setStartDelay(200 * i);
//anim.setRepeatCount(ValueAnimator.INFINITE); anims.add(anim);
}
arrowAnim =new AnimatorSet();
arrowAnim.playTogether(anims);
arrowAnim.addListener(new AnimatorListenerAdapter() {
private long startTime;
private Runnablerestarter =new Runnable() {
@Override public void run() {
if (arrowAnim !=null) {
arrowAnim.start();
}
}
};
@Override public void onAnimationEnd(Animator animation) {
if (System.currentTimeMillis() -startTime <
animation.getDuration() /4) {
if (BuildVars.LOGS_ENABLED) {
FileLog.w("Not repeating animation because previous loop
was too fast");
}
return;
}
if (!canceled &&animatingArrows)
post(restarter);
}
@Override public void onAnimationCancel(Animator animation) {
canceled =true;
}
@Override public void onAnimationStart(Animator animation) {
startTime = System.currentTimeMillis();
}
});
}
@Override protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (arrowAnim !=null) {
canceled =true;
arrowAnim.cancel();
arrowAnim =null;
}
}
public void setColor(int color) {
pullBgPaint.setColor(color);
pullBgPaint.setAlpha(0xB2);
}
public void setViewToDrag(View viewToDrag,boolean dragFromRight) {
this.viewToDrag = viewToDrag;
this.dragFromRight = dragFromRight;
updateArrowPath();
}
public void setListener(Listener listener) {
this.listener = listener;
}
private int getDraggedViewWidth() {
return getHeight();
}
@Override public boolean onTouchEvent(MotionEvent ev) {
if (!isEnabled())
return false;
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
if ((!dragFromRight && ev.getX() < getDraggedViewWidth()) ||
(dragFromRight && ev.getX() > getWidth() - getDraggedViewWidth())) {
dragging =true;
dragStartX = ev.getX();
getParent().requestDisallowInterceptTouchEvent(true);
listener.onDragStart();
stopAnimatingArrows();
}
}else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
viewToDrag.setTranslationX(Math.max(dragFromRight ? -(getWidth() -
getDraggedViewWidth()) :0, Math.min(ev.getX() -dragStartX,dragFromRight ?0 :
(getWidth() - getDraggedViewWidth()))));
invalidate();
}else if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction()
== MotionEvent.ACTION_CANCEL) {
if (Math.abs(viewToDrag.getTranslationX()) >= getWidth() -
getDraggedViewWidth() && ev.getAction() == MotionEvent.ACTION_UP) {
listener.onDragComplete();
}else {
listener.onDragCancel();
viewToDrag.animate().translationX(0).setDuration(200).start();
invalidate();
startAnimatingArrows();
dragging =false;
}
}
//Здесь должно возвращаться значение переменнойdragging,но это вроде
блокирует двойной тап.
return super.onTouchEvent(ev);
}
public void stopAnimatingArrows() {
animatingArrows =false;
}
public void startAnimatingArrows() {
if (animatingArrows ||arrowAnim ==null)
return;
animatingArrows =true;
if (arrowAnim !=null) {
arrowAnim.start();
}
}
public void reset() {
if (arrowAnim ==null ||canceled) {
return;
}
listener.onDragCancel();
viewToDrag.animate().translationX(0).setDuration(200).start();
invalidate();
startAnimatingArrows();
dragging =false;
}
@Override protected void onDraw(Canvas canvas) {
if (viewToDrag.getTranslationX() !=0) {
if (dragFromRight) {
tmpRect.set(getWidth() +viewToDrag.getTranslationX() -
getDraggedViewWidth(),0, getWidth(), getHeight());
}else {
tmpRect.set(0,0,viewToDrag.getTranslationX() +
getDraggedViewWidth(), getHeight());
}
canvas.drawRoundRect(tmpRect, getHeight() /2, getHeight()
/2,pullBgPaint);
}
canvas.save();
if (dragFromRight) {
canvas.translate(getWidth() - getHeight() - AndroidUtilities.dp(12
+6), getHeight() /2);
}else {
canvas.translate(getHeight() + AndroidUtilities.dp(12),
getHeight() /2);
}
float offsetX = Math.abs(viewToDrag.getTranslationX());
for (int i =0; i <3; i++) {
float masterAlpha =1;
if (offsetX > AndroidUtilities.dp(16 * i)) {
masterAlpha =1 - Math.min(1, Math.max(0, (offsetX - i *
AndroidUtilities.dp(16)) / AndroidUtilities.dp(16)));
}
arrowsPaint.setAlpha(Math.round(arrowAlphas[i] * masterAlpha));
canvas.drawPath(arrow,arrowsPaint);
canvas.translate(AndroidUtilities.dp(dragFromRight ? -16 :16),0);
}
canvas.restore();
invalidate();
}
private void updateArrowPath() {
arrow.reset();
int size = AndroidUtilities.dp(6);
if (dragFromRight) {
arrow.moveTo(size, -size);
arrow.lineTo(0,0);
arrow.lineTo(size, size);
}else {
arrow.moveTo(0, -size);
arrow.lineTo(size,0);
arrow.lineTo(0, size);
}
}
@Override public void
onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info){
super.onInitializeAccessibilityNodeInfo(info);
info.addAction(AccessibilityNodeInfo.ACTION_CLICK) ;
}
//action click почему-то не возникает.
@Override public boolean performAccessibilityAction(int action, Bundle
arguments){
if(action==AccessibilityNodeInfo.ACTION_CLICK && isEnabled()){
listener.onDragComplete();
}
return super.performAccessibilityAction(action, arguments);
}
//Этот метод был добавлен мной.
@Override public boolean performClick() {
if(isEnabled()) {
listener.onDragComplete();
}
return super.performClick();
}
public interface Listener {
void onDragComplete();
void onDragStart();
void onDragCancel();
}
private class ArrowAnimWrapper {
private int index;
public ArrowAnimWrapper(int value) {
index = value;
}
public int getArrowAlpha() {
return arrowAlphas[index];
}
public void setArrowAlpha(int value) {
arrowAlphas[index] = value;
}
}
}