Polls in compose

This commit is contained in:
Grishka
2022-02-13 00:29:15 +03:00
parent dc63d054dc
commit ce258f1b54
9 changed files with 374 additions and 5 deletions

View File

@@ -0,0 +1,121 @@
package org.joinmastodon.android.ui.views;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V;
public class ReorderableLinearLayout extends LinearLayout{
private static final String TAG="ReorderableLinearLayout";
private View draggedView;
private View bottomSibling, topSibling;
private float startY;
private OnDragListener dragListener;
public ReorderableLinearLayout(Context context){
super(context);
}
public ReorderableLinearLayout(Context context, @Nullable AttributeSet attrs){
super(context, attrs);
}
public ReorderableLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
}
public void startDragging(View child){
getParent().requestDisallowInterceptTouchEvent(true);
draggedView=child;
draggedView.animate().translationZ(V.dp(1f)).setDuration(150).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
int index=indexOfChild(child);
if(index==-1)
throw new IllegalArgumentException("view "+child+" is not a child of this layout");
if(index>0)
topSibling=getChildAt(index-1);
if(index<getChildCount()-1)
bottomSibling=getChildAt(index+1);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
if(draggedView!=null){
startY=ev.getY();
return true;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev){
if(draggedView!=null){
if(ev.getAction()==MotionEvent.ACTION_UP || ev.getAction()==MotionEvent.ACTION_CANCEL){
endDrag();
draggedView=null;
bottomSibling=null;
topSibling=null;
}else if(ev.getAction()==MotionEvent.ACTION_MOVE){
draggedView.setTranslationY(ev.getY()-startY);
if(topSibling!=null && draggedView.getY()<=topSibling.getY()){
moveDraggedView(-1);
}else if(bottomSibling!=null && draggedView.getY()>=bottomSibling.getY()){
moveDraggedView(1);
}
}
}
return super.onTouchEvent(ev);
}
private void endDrag(){
draggedView.animate().translationY(0f).translationZ(0f).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
}
private void moveDraggedView(int positionOffset){
int index=indexOfChild(draggedView);
int prevTop=draggedView.getTop();
removeView(draggedView);
int prevIndex=index;
index+=positionOffset;
addView(draggedView, index);
final View prevSibling=positionOffset<0 ? topSibling : bottomSibling;
int prevSiblingTop=prevSibling.getTop();
if(index>0)
topSibling=getChildAt(index-1);
else
topSibling=null;
if(index<getChildCount()-1)
bottomSibling=getChildAt(index+1);
else
bottomSibling=null;
dragListener.onSwapItems(prevIndex, index);
draggedView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){
draggedView.getViewTreeObserver().removeOnPreDrawListener(this);
float offset=prevTop-draggedView.getTop();
startY-=offset;
draggedView.setTranslationY(draggedView.getTranslationY()+offset);
prevSibling.setTranslationY(prevSiblingTop-prevSibling.getTop());
prevSibling.animate().translationY(0f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(200).start();
return true;
}
});
}
public void setDragListener(OnDragListener dragListener){
this.dragListener=dragListener;
}
public interface OnDragListener{
void onSwapItems(int oldIndex, int newIndex);
}
}