如何将视图引用传递到android自定义视图?
我是这样做的如何将视图引用传递到android自定义视图?,android,custom-view,Android,Custom View,我是这样做的 public class Viewee extends LinearLayout { public Viewee(Context context, AttributeSet a) { super(context, attributeSet); View.inflate(context, R.layout.main6, this); TextView textView = (TextView) findViewById(
public class Viewee extends LinearLayout
{
public Viewee(Context context, AttributeSet a)
{
super(context, attributeSet);
View.inflate(context, R.layout.main6, this);
TextView textView = (TextView) findViewById(R.id.custom_text);
TypedArray t = context.obtainStyledAttributes(a, R.styleable.Viewee);
int id = t.getResourceId(R.styleable.Viewee_linkedView, 0);
if (id != 0)
{
_id = id;
}
t.recycle();
}
private int _id;
public void Foo()
{
TextView textView = (TextView) findViewById(R.id.custom_text);
View view = getRootView().findViewById(_id);
textView.setText(((TextView) view).getText().toString());
}
}
1) 创建可设置样式的
<declare-styleable name="Viewee">
<attr name="linkedView" format="reference"/>
</declare-styleable>
最后在下面的活动中
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.ns"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tvTest"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="android"/>
<com.ns.Viewee
android:layout_width="fill_parent"
android:layout_height="fill_parent"
app:linkedView="@+id/tvTest"
/>
</LinearLayout>
现在,尽管我在VieweeConstractor中收到了一个非零的id
,但仍会发生findViewById(id)
retuns null和NullPointerException
我错过了什么
您所描述的
android:id
设置为app:linkedView=“@+id/tvTest
。但是,@+id/tvTest
用于创建名为“tvTest”的新id。您要做的是使用app:linkedView=“@id/tvTest我找到了答案
问题在于findViewById(id)
以及我在哪里调用它findViewById
只查找子视图,而不查找上面层次结构级别上存在的视图。所以我必须调用类似于getRootView().findViewById(id)
的东西,但它也返回null
,因为我调用它的地方不正确
在Viewee
中,constractorViewee
本身尚未附加到其根目录,因此调用会导致NullPointerException
因此,如果我在构造之后在其他地方调用getRootView().findViewById(id)
,它可以正常工作,“@+id/tvTest”
和“@id/tvTest”
都是正确的。我已经测试过了
答案如下
public class Viewee extends LinearLayout
{
public Viewee(Context context, AttributeSet a)
{
super(context, attributeSet);
View.inflate(context, R.layout.main6, this);
TextView textView = (TextView) findViewById(R.id.custom_text);
TypedArray t = context.obtainStyledAttributes(a, R.styleable.Viewee);
int id = t.getResourceId(R.styleable.Viewee_linkedView, 0);
if (id != 0)
{
_id = id;
}
t.recycle();
}
private int _id;
public void Foo()
{
TextView textView = (TextView) findViewById(R.id.custom_text);
View view = getRootView().findViewById(_id);
textView.setText(((TextView) view).getText().toString());
}
}
当需要通过活动中其他地方的引用id处理附加视图时,会调用Foo
这完全归功于那些参与其中的人。在提交问题之前,我没有看过那篇文章。我知道这是一个老问题,但我想我会添加另一种方法,因为我想将所有内容封装到我的自定义视图中
我没有从外部调用,这是在层次结构中获得更高视图的另一种方式,而是连接到onatachedtowindow()
:
public class MyCustomView extends LinearLayout {
private int siblingResourceId;
private View siblingView;
public MyCustomView(Context context, AttributeSet a) {
super(context, attributeSet);
inflate(context, R.layout.main6, this);
TextView textView = (TextView) findViewById(R.id.custom_text);
TypedArray t = context.obtainStyledAttributes(a, R.styleable.Viewee);
siblingResourceId = t.getResourceId(R.styleable.MyCustomView_siblingResourceId, NO_ID);
t.recycle();
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
if (siblingResourceId != NO_ID) {
siblingView = ((View) getParent()).findViewById(siblingResourceId);
}
}
}
onAttachedToWindow
很早就被调用了,但显然已经晚到了足以解决整个视图层次结构的地步。它至少可以完美地满足我的需求,而且更易于控制,工作时不需要外界的互动;-)
编辑:Kotlin代码已添加
class MyCustomView(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) {
private val siblingResourceId: Int
private lateinit var siblingView: View
// All other constructors left out for brevity.
init {
inflate(context, R.layout.main6, this)
val textView = findViewById<TextView>(R.id.custom_text)
val t = context.obtainStyledAttributes(a, R.styleable.Viewee)
siblingResourceId = t.getResourceId(R.styleable.MyCustomView_siblingResourceId, NO_ID)
t.recycle()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (siblingResourceId != NO_ID) {
siblingView = (parent as View).findViewById(siblingResourceId)
}
}
}
class MyCustomView(上下文:上下文,属性集:属性集):LinearLayout(上下文,属性集){
私有val同级资源ID:Int
私有lateinit变量同级视图:视图
//为了简洁起见,所有其他构造函数都省略了。
初始化{
充气(上下文,右布局图6,本)
val textView=findViewById(R.id.custom_text)
val t=context.actainStyledAttributes(a,R.styleable.Viewee)
siblingResourceId=t.getResourceId(R.styleable.MyCustomView\u siblingResourceId,无\u ID)
t、 回收()
}
覆盖附加到的日志(){
super.onAttachedToWindow()
if(同级资源ID!=无\u ID){
siblingView=(父视图)。findViewById(siblingResourceId)
}
}
}
注意:我们假设此自定义视图的父视图
本身就是一个视图
本身。我通过视图=findViewById(id)应用了您的答案代码>仍然返回null!为什么要使用id
保存视图的id?使用R.id.foo
而不是创建另一个变量应该相当简单。此外,我无法通过您的评论判断您是否将
元素的app:linkedView
属性更改为“@id/tvTest
。我必须保留id
,因为vieweee
是一个自定义视图,它引用了另一个视图作为原因。我不能像你说的那样将链接视图称为R.id.foo
。如果我在另一个不存在R.id.foo
的布局中使用Viewee
会怎么样?我也按照你的建议做了,并将@code>“@+id/tvTest”更改为“@id/tvTest”
,但没有成功。@+id而不是@id是不相关的,加号是fine不要将它放在onDraw
中,而是放在onAttachedToWindow
中。将其放置在onDraw中将每秒调用X次该方法,可能是每秒60次@DanielWilson您能删除您的评论吗?如果在上层有其他具有相同id的视图,则会得到该注释view@Alimohammadi不确定这是否有意义-如何使用2个相同的ID构建布局?不可能。想想活动中的片段。考虑我们在Acvivi.xml和Fract.xml文件中有相同的ID,这个返回视图是在activity@Alimohammadi它不相关,因为我们在自定义视图中,而不是片段
或活动
。这就是文档在视图
类中对findViewById
的描述:查找具有给定ID的第一个子视图,如果ID匹配{@link#getId()},则查找视图本身,如果ID无效(<0)或层次结构中没有匹配视图,则查找{@code null}。
class MyCustomView(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) {
private val siblingResourceId: Int
private lateinit var siblingView: View
// All other constructors left out for brevity.
init {
inflate(context, R.layout.main6, this)
val textView = findViewById<TextView>(R.id.custom_text)
val t = context.obtainStyledAttributes(a, R.styleable.Viewee)
siblingResourceId = t.getResourceId(R.styleable.MyCustomView_siblingResourceId, NO_ID)
t.recycle()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (siblingResourceId != NO_ID) {
siblingView = (parent as View).findViewById(siblingResourceId)
}
}
}