如何将视图引用传递到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
中,constractor
Viewee
本身尚未附加到其根目录,因此调用会导致
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) 
        }
    }
}