如何获得以编程方式扩展 RelativeLayout 的自定义组件?
How do I get a custom component that extends RelativeLayout programmatically?
刚接触Android以下问题让我发疯,无法Google回答表明解决方案非常简单...
我尝试通过代码将自定义组件(ArticleView
扩展 RelativeLayout
)添加到 ViewGroup
(LinearLayout
),但我无法访问 ArticleView
对象,尝试转换为它只会抛出一个
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.eo.read/com.example.eo.read.ArticleInfoActivity}: java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to com.example.eo.read.view.ArticleView
Caused by: java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to com.example.eo.read.view.ArticleView
at com.example.eo.read.ArticleInfoActivity.onCreate(ArticleInfoActivity.java:44)
在我的 Activity
class 中:
package com.example.eo.read;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.example.eo.read.content.Article;
import com.example.eo.read.content.ArticleDB;
import com.example.eo.read.view.ArticleView;
...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_article_info);
_article = ArticleDB.getInstance().getArticle("test");
LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//get the linear layout into which the ArticleView is going
LinearLayout container = (LinearLayout) findViewById(R.id.recommendation_container);
//get the custom component
RelativeLayout ra = (RelativeLayout)inflater.inflate(R.layout.article_view, container, false);
//this causes the classcast exception, although this RelativeLayout really should be an ArticleView
((ArticleView)ra).setArticle(_article);
//adding the ArticleView to the container works fine, and the customizations
//I have made in ArticleView are visible, so indeed it seems ra is an ArticleView ??
container.addView(ra);
}
(简体)article_view.xml
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="260dp" android:layout_height="wrap_content" android:background="@drawable/stroked_grey_plate">
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:textSize="16sp"
android:text="Sample text"
android:textColor="#111111"
android:scrollHorizontally="true"
android:ellipsize="end"
android:maxLines="1"
/>
</RelativeLayout>
activity 的布局包含要插入 ArticleView
的 id/recommedation_container。下面也是以声明方式插入的相同视图,只是为了清楚起见:
<LinearLayout
android:id="@+id/recommendation_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="10dp">
<com.example.eo.read.view.ArticleView
android:layout_width="wrap_content" android:layout_height="wrap_content"
custom:titleText="my title text"
/>
</LinearLayout>
ArticleView
class 本质上是:
package com.example.eo.read.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.example.eo.read.R;
import com.example.eo.read.content.Article;
public class ArticleView extends RelativeLayout {
private TextView _titleView;
private Article _article;
public ArticleView(Context context) {
this(context,null);
}
public ArticleView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ArticleView, 0, 0);
//in the case where the ArticleView is declared in XML the title is retreived from a custom attribute, this works fine.
String titleText = a.getString(R.styleable.ArticleView_titleText);
a.recycle();
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.article_view, this, true);
ViewGroup rl = (ViewGroup)getChildAt(0); //get the RelativeLayout
_titleView = (TextView) rl.getChildAt(0);
_titleView.setText(titleText);
}
//in the case where the ArticleView is initiated from code the title should be set by calling this method,
//which I never can reach since I cannot get to this ArticleView object from my activity :-(
//I realize this class is maybe not fully functional yet but first step is to actually be able to initiate it...
public void setArticle(Article a) {
_article = a;
_titleView.setText(_article.getTitle());
}
}
所以,我的问题差不多.. 为什么我做不到:
ArticleView ra = (ArticleView)inflater.inflate(R.layout.article_view, container, false);
我应该怎么做才能到达我的 ArticleView
?
如果我理解正确,您想以编程方式添加自定义视图,而不是在 XML?
中定义它
如果是这种情况,如果您只是这样做会发生什么:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_article_info);
_article = ArticleDB.getInstance().getArticle("test");
LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//get the linear layout into which the ArticleView is going
LinearLayout container = (LinearLayout) findViewById(R.id.recommendation_container);
//get the custom component
ArticleView av = new ArticleView(this);
av.setArticle(_article);
container.addView(av);
}
如果您还没有偶然发现它,这个博客似乎有一些关于自定义视图的不错的提示:http://trickyandroid.com/protip-inflating-layout-for-your-custom-view/
如果你想让你的自定义视图与你的布局一起膨胀,那么你可以这样做:
<LinearLayout
android:id="@+id/recommendation_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="10dp">
<com.example.eo.read.view.ArticleView
android:id="@+id/article"
android:layout_width="wrap_content" android:layout_height="wrap_content"
custom:titleText="my title text"
/>
</LinearLayout>
仅以您问题中的 XML 为例,不确定它是否适合您的情况。
但是现在,将上面的 XML 膨胀到一个名为 root
的视图,然后执行 root.findViewById(R.id.article)
应该 return 一个可以转换为 ArticleView 的视图.
想一想,如果你有这样一个 XML 文件:
<com.example.eo.read.view.ArticleView
android:layout_width="wrap_content" android:layout_height="wrap_content"
custom:titleText="my title text"
/>
您实际上应该能够像您尝试的那样膨胀它,并转换为 ArticleView,因为 com.example.eo.read.view.ArticleView 现在是布局的根。
将 XML 文件中的 ArticleView
替换为 [packagename].ArticleView
例如,如果您的ArticleView
class包含在com.john.article
中,那么您的ArticleView
应该替换为com.john.article.ArticleView
。
刚接触Android以下问题让我发疯,无法Google回答表明解决方案非常简单...
我尝试通过代码将自定义组件(ArticleView
扩展 RelativeLayout
)添加到 ViewGroup
(LinearLayout
),但我无法访问 ArticleView
对象,尝试转换为它只会抛出一个
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.eo.read/com.example.eo.read.ArticleInfoActivity}: java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to com.example.eo.read.view.ArticleView
Caused by: java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to com.example.eo.read.view.ArticleView
at com.example.eo.read.ArticleInfoActivity.onCreate(ArticleInfoActivity.java:44)
在我的 Activity
class 中:
package com.example.eo.read;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.example.eo.read.content.Article;
import com.example.eo.read.content.ArticleDB;
import com.example.eo.read.view.ArticleView;
...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_article_info);
_article = ArticleDB.getInstance().getArticle("test");
LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//get the linear layout into which the ArticleView is going
LinearLayout container = (LinearLayout) findViewById(R.id.recommendation_container);
//get the custom component
RelativeLayout ra = (RelativeLayout)inflater.inflate(R.layout.article_view, container, false);
//this causes the classcast exception, although this RelativeLayout really should be an ArticleView
((ArticleView)ra).setArticle(_article);
//adding the ArticleView to the container works fine, and the customizations
//I have made in ArticleView are visible, so indeed it seems ra is an ArticleView ??
container.addView(ra);
}
(简体)article_view.xml
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="260dp" android:layout_height="wrap_content" android:background="@drawable/stroked_grey_plate">
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:textSize="16sp"
android:text="Sample text"
android:textColor="#111111"
android:scrollHorizontally="true"
android:ellipsize="end"
android:maxLines="1"
/>
</RelativeLayout>
activity 的布局包含要插入 ArticleView
的 id/recommedation_container。下面也是以声明方式插入的相同视图,只是为了清楚起见:
<LinearLayout
android:id="@+id/recommendation_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="10dp">
<com.example.eo.read.view.ArticleView
android:layout_width="wrap_content" android:layout_height="wrap_content"
custom:titleText="my title text"
/>
</LinearLayout>
ArticleView
class 本质上是:
package com.example.eo.read.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.example.eo.read.R;
import com.example.eo.read.content.Article;
public class ArticleView extends RelativeLayout {
private TextView _titleView;
private Article _article;
public ArticleView(Context context) {
this(context,null);
}
public ArticleView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ArticleView, 0, 0);
//in the case where the ArticleView is declared in XML the title is retreived from a custom attribute, this works fine.
String titleText = a.getString(R.styleable.ArticleView_titleText);
a.recycle();
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.article_view, this, true);
ViewGroup rl = (ViewGroup)getChildAt(0); //get the RelativeLayout
_titleView = (TextView) rl.getChildAt(0);
_titleView.setText(titleText);
}
//in the case where the ArticleView is initiated from code the title should be set by calling this method,
//which I never can reach since I cannot get to this ArticleView object from my activity :-(
//I realize this class is maybe not fully functional yet but first step is to actually be able to initiate it...
public void setArticle(Article a) {
_article = a;
_titleView.setText(_article.getTitle());
}
}
所以,我的问题差不多.. 为什么我做不到:
ArticleView ra = (ArticleView)inflater.inflate(R.layout.article_view, container, false);
我应该怎么做才能到达我的 ArticleView
?
如果我理解正确,您想以编程方式添加自定义视图,而不是在 XML?
中定义它如果是这种情况,如果您只是这样做会发生什么:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_article_info);
_article = ArticleDB.getInstance().getArticle("test");
LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//get the linear layout into which the ArticleView is going
LinearLayout container = (LinearLayout) findViewById(R.id.recommendation_container);
//get the custom component
ArticleView av = new ArticleView(this);
av.setArticle(_article);
container.addView(av);
}
如果您还没有偶然发现它,这个博客似乎有一些关于自定义视图的不错的提示:http://trickyandroid.com/protip-inflating-layout-for-your-custom-view/
如果你想让你的自定义视图与你的布局一起膨胀,那么你可以这样做:
<LinearLayout
android:id="@+id/recommendation_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="10dp">
<com.example.eo.read.view.ArticleView
android:id="@+id/article"
android:layout_width="wrap_content" android:layout_height="wrap_content"
custom:titleText="my title text"
/>
</LinearLayout>
仅以您问题中的 XML 为例,不确定它是否适合您的情况。
但是现在,将上面的 XML 膨胀到一个名为 root
的视图,然后执行 root.findViewById(R.id.article)
应该 return 一个可以转换为 ArticleView 的视图.
想一想,如果你有这样一个 XML 文件:
<com.example.eo.read.view.ArticleView
android:layout_width="wrap_content" android:layout_height="wrap_content"
custom:titleText="my title text"
/>
您实际上应该能够像您尝试的那样膨胀它,并转换为 ArticleView,因为 com.example.eo.read.view.ArticleView 现在是布局的根。
将 XML 文件中的 ArticleView
替换为 [packagename].ArticleView
例如,如果您的ArticleView
class包含在com.john.article
中,那么您的ArticleView
应该替换为com.john.article.ArticleView
。