繁体   English   中英

Android UI:自定义GIF视图在RelativeLayout中的位置

[英]Android UI: Positioning of custom GIF View within RelativeLayout

因此,我创建了自己的自定义GIFView组件以显示动画GIF。 我的问题是Android无法将其正确放置在中央位置。 我试图从各种来源寻找这种方法,但是大多数都是关于如何动态地执行此操作的,而我想仅使用XML布局来执行此操作。

问题是这样的:

  1. 如果我不覆盖“ onMeasure()”,那么我的GIFView似乎占据了屏幕上的所有空间。 这导致布局中的所有元素都绘制到屏幕的最上方。 我的GIF就像一个进度条(高度= 8像素,宽度= 152像素),因此它不需要太多的高度。 无论如何,Android都会这样考虑并给出整个屏幕(我的解释是基于onMeasure方法的MeasureSpecs)。 动画现在位于TextView下方,但不在中心区域。 相反,它位于该区域的左上角。

  2. 如果我确实覆盖了“ onMeasure()”,则在屏幕中间及其下方的进度动画中将正确绘制TextView。 但是,在这种情况下,动画GIF的位置也在该区域的左上方,而它应该在该区域的中间。

  3. 如果确实覆盖了“ onMeasure()”,然后根据需要通过调用“ setMeasuredDimension()”来设置度量,但是不调用super.onMeasure(),则其行为与情况(1)相同。 这意味着布局占据了整个屏幕,而我的TextView可以从屏幕的顶部找到。

我不确定我是否有意义,所以我尝试在数学上为您提供这个想法(由于我是新用户,所以我无法发布屏幕截图)。 因此,相对布局提供了TextView下方的区域,该区域与屏幕一样宽(screenWidth),并且与所需的高度一样高(paddingTop + paddingBottom + GIFView.getHeight())。 现在,我希望看到动画从以下位置开始绘制:(x = paddingLeft +(screenWidth-paddingLeft-paddingRight-GIFView.getWidth())/ 2)和(y = paddingTop)。 相反,我看到Android将其绘制到位置(x = 0)和(y = 0)。

我确信这里的问题是我刚刚忽略的,但是如果有人有时间研究这个问题,我将不胜感激。

所以,我得到这个问题的片段:

样式声明:

<declare-styleable name="GIFView">
    <attr name="resourceId" format="reference" />
</declare-styleable>

主布局XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical"
   android:paddingLeft="10dip"
   android:paddingRight="10dip"
   android:isScrollContainer="true"
   android:background="#EFEFEF" >  

   <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:custom="http://schemas.android.com/apk/res/com.myown.smthg"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_centerVertical="true"
      android:orientation="vertical"
      android:background="@drawable/background_white_gray"
      android:paddingLeft="16dip"
      android:paddingRight="16dip"
      android:isScrollContainer="true" >

  <TextView
     android:id="@+id/TextViewWaitReason"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
         android:gravity="center"
         android:paddingTop="12dip"
         android:paddingLeft="12dip"
         android:paddingRight="12dip"
         android:textColor="#343434"
         android:textSize="20sp" />

  <com.myown.smthg.util.GIFView
     custom:resourceId="@drawable/progress_bar"
     android:id="@+id/progressGIF"
     android:layout_below="@id/TextViewWaitReason"
     android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
         android:gravity="center"
         android:paddingTop="0dip"
         android:paddingLeft="24dip"
         android:paddingRight="24dip"
         android:paddingBottom="16dip" />
  </RelativeLayout>

然后是GIFView.java的代码:

public class GIFView extends View {
// The resource id of the GIF
private int mResourceId;

// Movie to be shown
private Movie mMovie;
private long mStartTime;

// Size of this View
private int mHeight, mWidth;

/**
 * Constructor
 * 
 * @param context
 * @param attributes
 */
public GIFView( Context context, AttributeSet attributes ) {
    super( context, attributes );

    // Get the attribute for resource id
    TypedArray t = context.getTheme().obtainStyledAttributes( 
            attributes, R.styleable.GIFView, 0, 0 );

    mResourceId = -1;
    mMovie = null;
    mStartTime = 0;
    mHeight = 0;
    mWidth = 0;

    // This call might fail
    try
    {
        mResourceId = t.getResourceId ( R.styleable.GIFView_resourceId, -1 );

        mMovie = Movie.decodeStream( context.getResources().openRawResource( mResourceId ) );
        if( mMovie != null )
        {
            mWidth = mMovie.width();
            mHeight = mMovie.height();
        }
    }
    finally
    {
        t.recycle();
    }
}

@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{   
    final int desiredHSpec = MeasureSpec.makeMeasureSpec( mHeight, MeasureSpec.EXACTLY );
    final int desiredWSpec = MeasureSpec.makeMeasureSpec( mWidth, MeasureSpec.EXACTLY );
    setMeasuredDimension( desiredWSpec, desiredHSpec );

    super.onMeasure( desiredWSpec, desiredHSpec );
}

@Override
protected void onDraw( Canvas canvas )
{
    super.onDraw( canvas );

    // Return if we have no movie
    if( mMovie == null ) return;

    // Catch the time now
    long now = System.currentTimeMillis();

    // Catch the start time if needed
    if( mStartTime == 0 ) mStartTime = now;

    int relTime = (int)( (now- mStartTime) % mMovie.duration() );
    mMovie.setTime( relTime );
    mMovie.draw( canvas, 0, 0 );

    this.invalidate();
}

}

如果这很重要,那么活动构造函数如下所示:

super.onCreate( savedInstanceState );
// Set the content view
setContentView( R.layout.layout_wait );

// Get the String to be shown
Intent intent = getIntent();
String waitStr = intent.getStringExtra( myService.EXTRA_TEXT );

// Set the done text
TextView t = (TextView)findViewById( R.id.TextViewWaitReason );
if( t != null && waitStr != null )
    t.setText( waitStr );

那么,为什么不能让该动画在文本下方和屏幕中央运行? 如果可以先弄清楚,我将在此处发布此修复程序...它与onMeasure()方法有关,因为覆盖它会更改所有内容。

代码段免责声明:我不会在inDraw()的末尾留下那个invalidate()...

Br,特木

好的,感谢所有有时间调查此问题的人员。 我也是这样做的,而且正如我所期望的,解决方案非常简单...

问题是我没有为View声明正确的大小,只是声明它与GIF一样宽。 因此,将onMeasure固定为设置尺寸以采用所有给定宽度,然后考虑填充并绘制正确的位置以固定所有内容。 固定代码段:

新变量:

private int mDrawLeftPos;

固定onMeasure

@Override
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec )
{   
    int p_top = this.getPaddingTop(), p_bottom = this.getPaddingBottom();

    // Calculate new desired height
    final int desiredHSpec = MeasureSpec.makeMeasureSpec( mHeight + p_top + p_bottom , MeasureSpec.EXACTLY );

    setMeasuredDimension( widthMeasureSpec, desiredHSpec );
    super.onMeasure( widthMeasureSpec, desiredHSpec );

    // Update the draw left position
    mDrawLeftPos = Math.max( ( this.getWidth() - mWidth ) / 2, 0) ;
}

固定的onDraw

@Override
protected void onDraw( Canvas canvas )
{
    super.onDraw( canvas );

    // Return if we have no movie
    if( mMovie == null ) return;

    // Catch the time now
    long now = System.currentTimeMillis();

    // Catch the start time if needed
    if( mStartTime == 0 ) mStartTime = now;

    int relTime = (int)( (now- mStartTime) % mMovie.duration() );
    mMovie.setTime( relTime );
    mMovie.draw( canvas, mDrawLeftPos, this.getPaddingTop() );
}

Br,特木

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM