我尝试使用扩展ViewGroup的Customlayout实现像draggable面板一样的youtube。我已经使用onTouchEvents来创建和缩放拖动效果。
现在,问题在于,当拖动时,所选项目位于屏幕底部附近,就像在YouTube中一样。当在该位置点击该项目时,它应该返回到全屏模式。但为此,我为视图实现了onClicklistener,但它根本没有响应。
另外,在底部时,如何限制它在垂直方向上的移动,并允许它在YouTube中沿水平方向移动。
这是名为DraggablePanel的CustomLayout类。
package visio.com.eventpage;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.Toast;
import static android.view.MotionEvent.INVALID_POINTER_ID;
/**
* Created by Rambo on 1/9/2018.
*/
public class DraggablePanel extends ViewGroup {
public final ViewDragHelper mDragHelper;
public View mHeaderView;
private View mDescView;
private float mInitialMotionX;
private float mInitialMotionY;
private int mDragRange;
private int mTop;
private float mDragOffset;
private Context context;
public int toponViewReleased;
public int screenWidth, screenHeight;
private String TAG = "DraggablePanel";
public void manualInvalidate(){
invalidate();
}
public DraggablePanel(Context context) {
this(context, null);
}
public DraggablePanel(Context context, AttributeSet attrs) {
this(context, attrs, 0);
this.context = context;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mHeaderView = findViewById(R.id.viewHeader);
mDescView = findViewById(R.id.viewDesc);
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
screenHeight = displayMetrics.heightPixels;
screenWidth = displayMetrics.widthPixels;
}
public DraggablePanel(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDragHelper = ViewDragHelper.create(this, 1f, new DragHelperCallback());
}
private class DragHelperCallback extends ViewDragHelper.Callback {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == mHeaderView;
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
mTop = top;
float paddingOffset = (float)top/10;
mDragOffset = (float) top / mDragRange;
mHeaderView.setPivotX(mHeaderView.getWidth());
mHeaderView.setPivotY(mHeaderView.getHeight());
mHeaderView.setScaleX(1 - mDragOffset / 2);
mHeaderView.setScaleY(1 - mDragOffset / 2);
mHeaderView.setPadding(0,0,(int) paddingOffset, (int) paddingOffset);
mDescView.setAlpha(1 - mDragOffset);
if( top == 0){
}
requestLayout();
Log.d("onViewPositionChanged","Called");
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
int top = releasedChild.getTop()>screenHeight/3?screenHeight-150 - mHeaderView.getHeight():0;
Log.d("Heights","H1"+getHeight() + "child height" + releasedChild.getMeasuredHeight()+"top" +top);
mDragHelper.smoothSlideViewTo(releasedChild, releasedChild.getLeft(),top);
if( top!=0 ){
mDescView.setAlpha(0);
}
ViewCompat.postInvalidateOnAnimation(releasedChild);
toponViewReleased = top;
invalidate();
}
@Override
public int getViewVerticalDragRange(View child) {
return mDragRange;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
float descViewAlpha = mDescView.getAlpha();
final int topBound = getPaddingTop();
final int bottomBound = getHeight() - mHeaderView.getHeight() - 20;
int newTop = Math.min(Math.max(top, topBound), bottomBound);
if( descViewAlpha == 0 ){
newTop = 0;
}
Log.d(TAG,"clampVertical" + newTop);
return newTop;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
final int rightBound = mHeaderView.getPaddingRight();
final int leftBound = screenWidth - mHeaderView.getWidth() - 20;
int newTop = Math.min(Math.max(left, rightBound), leftBound);
if(mDescView.getAlpha() != 0){
newTop = 0;
}
Log.d(TAG,"clampHorizontal" + newTop);
return newTop;
}
}
@Override
public void computeScroll() {
if (mDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getActionMasked();
if (( action != MotionEvent.ACTION_DOWN)) {
mDragHelper.cancel();
return super.onInterceptTouchEvent(ev);
}
final float x = ev.getX();
final float y = ev.getY();
boolean interceptTap = false;
switch (action) {
case MotionEvent.ACTION_DOWN: {
mInitialMotionX = x;
mInitialMotionY = y;
interceptTap = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);
break;
}
case MotionEvent.ACTION_MOVE: {
final float adx = Math.abs(x - mInitialMotionX);
final float ady = Math.abs(y - mInitialMotionY);
final int slop = mDragHelper.getTouchSlop();
if (ady > slop && adx > ady) {
mDragHelper.cancel();
return false;
}
}
}
return mDragHelper.shouldInterceptTouchEvent(ev) || interceptTap;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
mDragHelper.processTouchEvent(ev);
final int action = ev.getAction();
final float x = ev.getX();
final float y = ev.getY();
boolean isHeaderViewUnder = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);
switch (action & ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mInitialMotionX = x;
mInitialMotionY = y;
break;
}
}
return isHeaderViewUnder && isViewHit(mHeaderView, (int) x, (int) y) || isViewHit(mDescView, (int) x, (int) y);
}
@Override
public boolean performClick() {
super.performClick();
if(toponViewReleased !=0){
mDragHelper.smoothSlideViewTo(mHeaderView, 0,0);
invalidate();
Log.d("DraggablePanel","Clicked top != 0");
}else{
Log.d("DraggablePanel","Clicked top == 0");
}
return true;
}
private boolean isViewHit(View view, int x, int y) {
int[] viewLocation = new int[2];
view.getLocationOnScreen(viewLocation);
int[] parentLocation = new int[2];
this.getLocationOnScreen(parentLocation);
int screenX = parentLocation[0] + x;
int screenY = parentLocation[1] + y;
return screenX >= viewLocation[0] && screenX < viewLocation[0] + view.getWidth() &&
screenY >= viewLocation[1] && screenY < viewLocation[1] + view.getHeight();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.d(TAG,"onLayout Called");
mDragRange = getHeight() - mHeaderView.getHeight();
mHeaderView.layout(
0,
mTop,
r,
mTop + mHeaderView.getMeasuredHeight());
mDescView.layout(
0,
mTop + mHeaderView.getMeasuredHeight(),
r,
mTop + b);
}
}
以下是使用上述类的布局。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerViewEvents"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<visio.com.eventpage.DraggablePanel
android:id="@+id/draggablePanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:id="@+id/viewHeader"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginEnd="20dp"
android:gravity="center"
android:scaleType="fitXY"
android:src="@drawable/ic_event" />
<TextView
android:id="@+id/viewDesc"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF00FF"
android:gravity="center"
android:tag="desc"
android:text="Loreum Loreum"
android:textColor="@android:color/white"
android:textSize="35sp" />
</visio.com.eventpage.DraggablePanel>
</FrameLayout>