2017-02-01 1 views
0

でカスタムビューで親を無視してmatch_parentデッドリンク。チュートリアルの著者は、YouTubeのAndroidアプリプレイヤーの行動に似ViewDragHelperを作成する方法について説明し、これらは彼が子供たちは、私は最近、カスタムビューを勉強し、一の具体例は、ここにあるチュートリアルから出て動作するようにしようとしているviewdraghelper

activity_main.xml

<FrameLayout 

    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

<ListView 
     android:id="@+id/listView" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:tag="list" 
     /> 

<com.example.vdh.YoutubeLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:id="@+id/youtubeLayout" 
     android:orientation="vertical" 
     android:visibility="visible"> 

    <TextView 
      android:id="@+id/viewHeader" 
      android:layout_width="match_parent" 
      android:layout_height="128dp" 
      android:fontFamily="sans-serif-thin" 
      android:textSize="25sp" 
      android:tag="text" 
      android:gravity="center" 
      android:textColor="@android:color/white" 
      android:background="#AD78CC"/> 

    <TextView 
      android:id="@+id/viewDesc" 
      android:tag="desc" 
      android:textSize="35sp" 
      android:gravity="center" 
      android:text="Loreum Loreum" 
      android:textColor="@android:color/white" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:background="#FF00FF"/> 

</com.example.vdh.YoutubeLayout> 

YoutubeLayout.java

public class YoutubeLayout extends ViewGroup { 

    private final ViewDragHelper mDragHelper; 

    private View mHeaderView; 
    private View mDescView; 

    private float mInitialMotionX; 
    private float mInitialMotionY; 

    private int mDragRange; 
    private int mTop; 
    private float mDragOffset; 


    public YoutubeLayout(Context context) { 
     this(context, null); 
    } 

    public YoutubeLayout(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); 
    } 

    @Override 
    protected void onFinishInflate() { 
     mHeaderView = findViewById(R.id.viewHeader); 
     mDescView = findViewById(R.id.viewDesc); 
    } 

    public YoutubeLayout(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     mDragHelper = ViewDragHelper.create(this, 1f, new DragHelperCallback()); 
    } 

    public void maximize() { 
     smoothSlideTo(0f); 
    } 

    boolean smoothSlideTo(float slideOffset) { 
     final int topBound = getPaddingTop(); 
     int y = (int) (topBound + slideOffset * mDragRange); 

     if (mDragHelper.smoothSlideViewTo(mHeaderView, mHeaderView.getLeft(), y)) { 
      ViewCompat.postInvalidateOnAnimation(this); 
      return true; 
     } 
     return false; 
    } 

    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; 

      mDragOffset = (float) top/mDragRange; 

      mHeaderView.setPivotX(mHeaderView.getWidth()); 
      mHeaderView.setPivotY(mHeaderView.getHeight()); 
      mHeaderView.setScaleX(1 - mDragOffset/2); 
      mHeaderView.setScaleY(1 - mDragOffset/2); 

      mDescView.setAlpha(1 - mDragOffset); 

      requestLayout(); 
     } 

     @Override 
     public void onViewReleased(View releasedChild, float xvel, float yvel) { 
      int top = getPaddingTop(); 
      if (yvel > 0 || (yvel == 0 && mDragOffset > 0.5f)) { 
       top += mDragRange; 
      } 
      mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top); 
     } 

     @Override 
     public int getViewVerticalDragRange(View child) { 
      return mDragRange; 
     } 

     @Override 
     public int clampViewPositionVertical(View child, int top, int dy) { 
      final int topBound = getPaddingTop(); 
      final int bottomBound = getHeight() - mHeaderView.getHeight() - mHeaderView.getPaddingBottom(); 

      final int newTop = Math.min(Math.max(top, topBound), bottomBound); 
      return newTop; 
     } 

    } 

    @Override 
    public void computeScroll() { 
     if (mDragHelper.continueSettling(true)) { 
      ViewCompat.postInvalidateOnAnimation(this); 
     } 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     final int action = MotionEventCompat.getActionMasked(ev); 

     if ((action != MotionEvent.ACTION_DOWN)) { 
      mDragHelper.cancel(); 
      return super.onInterceptTouchEvent(ev); 
     } 

     if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 
      mDragHelper.cancel(); 
      return false; 
     } 

     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 & MotionEventCompat.ACTION_MASK) { 
      case MotionEvent.ACTION_DOWN: { 
       mInitialMotionX = x; 
       mInitialMotionY = y; 
       break; 
      } 

      case MotionEvent.ACTION_UP: { 
       final float dx = x - mInitialMotionX; 
       final float dy = y - mInitialMotionY; 
       final int slop = mDragHelper.getTouchSlop(); 
       if (dx * dx + dy * dy < slop * slop && isHeaderViewUnder) { 
        if (mDragOffset == 0) { 
         smoothSlideTo(1f); 
        } else { 
         smoothSlideTo(0f); 
        } 
       } 
       break; 
      } 
     } 


     return isHeaderViewUnder && isViewHit(mHeaderView, (int) x, (int) y) || isViewHit(mDescView, (int) x, (int) y); 
    } 


    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) { 
     mDragRange = getHeight() - mHeaderView.getHeight(); 

     mHeaderView.layout(
       0, 
       mTop, 
       r, 
       mTop + mHeaderView.getMeasuredHeight()); 

     mDescView.layout(
       0, 
       mTop + mHeaderView.getMeasuredHeight(), 
       r, 
       mTop + b); 
    } 
} 

提供コードです著者はonLayoutonMeasureがひどく書かれていると私は推測しますこれらの1つ(またはその1つ)が子供の1人の問題の原因になっている可能性があります。

私の目的として、mDescViewTextViewを含むFramelayoutビューに置き換えました。どちらも高さがmatch_parentに設定されており、親(mDescView)の高さは正しく設定されていますが、その子(TextViewの内側はmDescView)は親の高さを無視し、高さを画面の高さ、違いを伝えることはできません)。これは問題です。mDescView子どもは、親によると、自分の身長を正しく調整することは決してありません。なぜなら、私は数日間の解決策を探していましたが、何も発見されず、研究によって私はなぜこれが起こったのかの理由。

これは、この問題の結果である、TextView高さは、その高さはmatch_parent

enter image description here

に設定した両方のにもかかわらず、その親mDescViewよりも大きい様子がわかりだから私の問題は私が得ることができるか、ですその親(または親)の子供(子供)が、彼らの両親の身長に合わせる必要があります。

可能であれば、著者が自分の方法のいくつかが最良/正しいものではなく、正しく/より良い方法で行われるべきだと考える理由を説明することができます。

答えて

0

私は最終的にこの問題を修正しましたが、これが正しい方法であるかどうかはまだ分かりません。私の解決策は、両方のビューの高さをonLayoutの間に設定することでした。 このメソッドは初めて呼び出されるため、このステートメントは初めて実行されるように設定しました(firstRuntrueの場合)

@Override 
protected void onLayout(boolean changed, int l, int t, int r, int b) { 
    mDragRange = getHeight() - mHeaderView.getHeight(); 

    if (firstRun) { 
     firstRun = false; 
     mDescView.getLayoutParams().height = getHeight() - mHeaderView.getMeasuredHeight(); 
    } 

    mHeaderView.layout(
      0, 
      mTop, 
      r, 
      mTop + mHeaderView.getMeasuredHeight()); 

    mDescView.layout(
      0, 
      mTop + mHeaderView.getMeasuredHeight(), 
      r, 
      mTop + b); 
} 
関連する問題