带孩子的自定义Android控件

Rom*_*ain 12 android border android-linearlayout

我试图创建一个定制的Android控制包含一个LinearLayout中.您可以将其视为具有花式边框,背景,左侧图像的扩展LinearLayout ...

我可以用XML完成所有工作(效果很好),但由于我的应用程序中有很多次出现,因此很难维护.我觉得这样的东西会更好:

/* Main.xml */
<MyFancyLayout>
    <TextView />   /* what goes inside my control's linear layout */
</MyfancyLayout>
Run Code Online (Sandbox Code Playgroud)

你会怎么做?我想避免在onMeasure/onLayout方法上重写整个线性布局.这就是我现在所拥有的:

/* MyFancyLayout.xml */
<TableLayout>
    <ImageView />
    <LinearLayout id="container" />   /* where I want the real content to go */
</TableLayout>    
Run Code Online (Sandbox Code Playgroud)

/* MyFancyLayout.java */
public class MyFancyLayout extends LinearLayout
{
    public MyFancyLayout(Context context) {
        super(context);
        View.inflate(context, R.layout.my_fancy_layout, this);
    }
}
Run Code Online (Sandbox Code Playgroud)

您如何在正确的位置(id =容器)插入用户指定的内容(main.xml中的T​​extView)?

干杯!

罗曼

-----编辑-------

仍然没有运气,所以我改变了我的设计,使用更简单的布局,并决定使用一些重复的XML.仍然非常感兴趣的人知道如何做到这一点!

est*_*why 10

这个确切的问题已经困扰了我一段时间了,但现在我才解决了这个问题.

乍一看,问题在于声明内容(在你的情况下是TextView) ctor 之后的某个时候实例化(我们通常会夸大我们的布局),所以现在声明和模板内容都太早了把前者推到后者里面.

我找到了一个可以操纵两者的地方:它是一个onFinishInflate()方法.以下是我的情况:

    @Override
    protected void onFinishInflate() {
        int index = getChildCount();
        // Collect children declared in XML.
        View[] children = new View[index];
        while(--index >= 0) {
            children[index] = getChildAt(index);
        }
        // Pressumably, wipe out existing content (still holding reference to it).
        this.detachAllViewsFromParent();
        // Inflate new "template".
        final View template = LayoutInflater.from(getContext())
            .inflate(R.layout.labeled_layout, this, true);
        // Obtain reference to a new container within "template".
        final ViewGroup vg = (ViewGroup)template.findViewById(R.id.layout);
        index = children.length;
        // Push declared children into new container.
        while(--index >= 0) {
            vg.addView(children[index]);
        }

        // They suggest to call it no matter what.
        super.onFinishInflate();
    }
Run Code Online (Sandbox Code Playgroud)

上面引用的labeled_layout.xml与以下内容不同:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation             ="vertical"
    android:layout_width            ="fill_parent"
    android:layout_height           ="wrap_content"
    android:layout_marginLeft       ="8dip"
    android:layout_marginTop        ="3dip"
    android:layout_marginBottom     ="3dip"
    android:layout_weight           ="1"
    android:duplicateParentState    ="true">

    <TextView android:id            ="@+id/label"
        android:layout_width        ="fill_parent"
        android:layout_height       ="wrap_content"
        android:singleLine          ="true"
        android:textAppearance      ="?android:attr/textAppearanceMedium"
        android:fadingEdge          ="horizontal"
        android:duplicateParentState="true" />

    <LinearLayout
        android:id                  ="@+id/layout"
        android:layout_width        ="fill_parent"
        android:layout_height       ="wrap_content"
        android:layout_marginLeft   ="8dip"
        android:layout_marginTop    ="3dip" 
        android:duplicateParentState="true" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

现在(仍然省略一些细节)我们可能会像这样使用它:

        <com.example.widget.LabeledLayout
            android:layout_width    ="fill_parent"
            android:layout_height   ="wrap_content">
            <!-- example content -->
        </com.example.widget.LabeledLayout> 
Run Code Online (Sandbox Code Playgroud)


JOG*_*JOG 7

这种方法为我节省了大量代码!:)

正如esteewhy所解释的那样,只需将xml定义的内容交换到您希望它们在您自己的布局中的位置onFinishInflate().例:

我把我在xml中指定的内容:

<se.jog.custom.ui.Badge ... >
    <ImageView ... />
    <TextView ... />
</se.jog.custom.ui.Badge>
Run Code Online (Sandbox Code Playgroud)

...并将它们移动到我希望它们所在的内部LinearLayout调用 contents:

public class Badge extends LinearLayout {
    //...
    private LinearLayout badge;
    private LinearLayout contents;

    // This way children can be added from xml.
    @Override
    protected void onFinishInflate() {      
        View[] children = detachChildren(); // gets and removes children from parent
        //...
        badge = (LinearLayout) layoutInflater.inflate(R.layout.badge, this);
        contents = (LinearLayout) badge.findViewById(R.id.badge_contents);
        for (int i = 0; i < children.length; i++)
            addView(children[i]); //overridden, se below.
        //...
        super.onFinishInflate();
    }

    // This way children can be added from other code as well.
    @Override
    public void addView(View child) {
        contents.addView(child);
}
Run Code Online (Sandbox Code Playgroud)

结合自定义XML属性,事物变得非常易于维护.


小智 0

只需使用这样的东西:

<org.myprogram.MyFancyLayout>
 ...
</org.myprogram.MyFancyLayout>
Run Code Online (Sandbox Code Playgroud)

有用的链接 - http://www.anddev.org/creating_custom_views__-_the_togglebutton-t310.html