因此,我创建了自己的自定义 GIFView 组件来显示动画 GIF。我的问题是 Android 无法将其正确放置到中心位置。我试图从各种来源中寻找这个,但大多数都是关于如何动态地做到这一点,而我想纯粹使用 XML 布局来做到这一点。
问题是这样的:
如果我不覆盖“onMeasure()”,那么我的 GIFView 似乎占据了屏幕上的所有空间。这导致布局中的所有元素都被绘制到屏幕的最顶部。我的 GIF 就像一个进度条(高度 = 8px,宽度 = 152px),所以它不会占用太多高度。无论如何,Android 是这么认为的,并给它整个屏幕(我的解释基于对 onMeasure 方法的 MeasureSpecs 的解释)。动画现在位于 TextView 下方,但不在中心区域。相反,它位于该区域的左上角。
如果我确实覆盖了“onMeasure()”,那么 TextView 将正确绘制在屏幕中间,并在其下方显示进度动画。但是,在这种情况下,动画 GIF 的位置也在该区域的左上角,而它应该在它的中间。
如果我确实覆盖了“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() 方法有关,因为覆盖它会改变一切。
片段免责声明:我不会在 onDraw() 的末尾留下那个 invalidate() ...
兄弟,提姆