EditText on demand小部件

时间:2012-07-30 13:13:41

标签: java android android-layout android-widget android-edittext

我想要一个TextView显示文本,当你单击/长按它时,文本框应该“显示”并允许编辑所述文本。当你完成编辑时(我猜想是onkey输入)它应该恢复为带有更新文本的文本视图......

我想知道实现这样的小部件是否可行或者我应该解决这个问题?提示和建议非常受欢迎。

如果您需要进一步了解我的意思,请转到您的(windows)skype个人资料并亲自看看。

编辑: 澄清:我特意要求一个小部件或者这样的文本视图直到被点击,然后转换为包含相同文本的edittext;完成编辑后,它会转换回表示新更改文本的textview。这就是我所说的“edittext on demand widget”。

但我希望得到比

更好的东西
public class Widget {
     TextView text;
     EditText edit;
     String   textToRepresent;
     //...
}

4 个答案:

答案 0 :(得分:4)

这里有几个不同的选择。

首先,您必须将onClick或onLongClick注册到要进行交互的TextView。 只需确保用户知道它是可点击的

然后让你的onClick函数启动DialogFragment。我喜欢创建show函数。请注意,您可以在此处使用支持库,使您的应用向后兼容。

private void showDialog() {
    MyDialogFragment dialog = new MyDialogFragment();
    dialog.show(getSupportFragmentManager(), "dialog");
}

DialogFragment非常简单。在onCreateView中,您将要向用户显示要显示的视图。如果您不想自定义,也可以使用简单的AlertDialogBuilder进行包装。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle     savedInstanceState) {
    View view = inflater.inflate(R.layout.your_dialog_layout);

    mTitleEditText = (TextView) view.findViewById(R.id.title);
    mTitleEditText.setOnClickListener(this);

    return view;
}

在findViewByIds设置onClickListeners之后。 您必须要处理的最后一件事是将数据恢复到原始TextView中。 您可以通过在Activity中创建一个可以从DialogFragment内部调用的公共方法来完成此操作。像这样的东西

 @Override
    public void onClick(View v) {
        int clickedId = v.getId();

        if (clickedId == mDoneButton.getId()) {
            MyActivity activity = (MyActivity)getActivity();

            mTitle = mTitleEditText.getText().toString();
            activity.setText(mTitle);
            dismiss();
        }
    }

我建议使用DialogFragment,因为它可以很好地处理你的生命周期。 但是,另一种选择是创建一个主题为对话框的新活动

<activity android:theme="@android:style/Theme.Dialog" />

然后您可以startActivityForResult显示对话框,然后在onActivityResult

中捕获结果

答案 1 :(得分:2)

这是我的解决方案。我只是给你一个基本的。在TextView和两个EditText ButtonOK前面创建Cancel(您可以像Skype一样更改为ImageButton)。改变两个视图的可见性。代码很简单,没有评论。您可以根据逻辑添加一些空检查。

public class CompoundTextView extends RelativeLayout implements OnClickListener {
private EditText edt;
private TextView txt;
RelativeLayout layout;

public SkypeTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    edt = (EditText) findViewById(R.id.edt);
    txt = (TextView) findViewById(R.id.txt_name);
    layout = (RelativeLayout) findViewById(R.id.layout);
    Button ok = (Button) findViewById(R.id.ok_btn);
    Button cancel = (Button) findViewById(R.id.cancel_btn);
    ok.setOnClickListener(this);
    cancel.setOnClickListener(this);
    txt.setOnClickListener(this);

}

public void onClick(View v) {
    // TODO Auto-generated method stub
    switch (v.getId()) {
    case R.id.ok_btn:
        String editString = edt.getText().toString();

        txt.setText(editString);
        layout.setVisibility(View.INVISIBLE);
        txt.setVisibility(View.VISIBLE);

        break;

    case R.id.cancel_btn:
        layout.setVisibility(View.INVISIBLE);
        txt.setVisibility(View.VISIBLE);
        break;
    case R.id.txt_name:
        txt.setVisibility(View.INVISIBLE);
        layout.setVisibility(View.VISIBLE);

        break;

    }

}

}

创建XML skypetextview。您可以自定义字体和背景,使其更漂亮。

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <TextView
        android:id="@+id/txt_name"
        android:layout_width="fill_parent"
        android:layout_height="100dp"
        android:textColor="#FFFFFF"
        android:textSize="14sp"
        android:background="#ff0000" />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="invisible"
        android:id="@+id/layout" >

        <EditText
            android:id="@+id/edt"
            android:layout_width="270dp"
            android:layout_height="100dp" />

        <Button
            android:id="@+id/ok_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/edt"
            android:text="OK" />

        <Button
            android:id="@+id/cancel_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/ok_btn"
            android:layout_toRightOf="@id/edt"
            android:text="Cancel" />
    </RelativeLayout>
</RelativeLayout>

将此视图添加(或包含)到您想要的布局。 示例:

public class TestActivity extends Activity  {   

SkypeTextView test;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LayoutInflater inflate = getLayoutInflater();
    test = (SkypeTextView ) inflate.inflate(R.layout.compound_text_view,
            null);
    setContentView(test);
}
PS:我忘记了。您应该为textview添加一些underline格式,以便用户注意到它是可点击的

答案 2 :(得分:0)

EditText根据其状态(可编辑或冻结)更改其背景。设置执行此操作的背景选择器。

使用此选择器xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_focused="true" android:drawable="@android:drawable/edit_text"/>
    <item android:drawable="@android:drawable/screen_background_light_transparent"/>
</selector>

答案 3 :(得分:0)

像我周四所说的那样...... Yul非常接近,但并不是很接近。他确实有一个相同的想法,但(理论上)过早地冲进代码;)

下面提供的TextBoxOnDemand代码是生产就绪的。这个想法类似于我想要在OP中避免的以及Yul建议的内容,但是具有最佳实现(例如使用ViewSwitcher而不是RelativeLayout)

我在以下文章中收集了所需的资源:

Creating custom view from xml

Declaring a custom android UI element using XML

Defining custom attrs

How to pass custom component parameters in java and xml

http://kevindion.com/2011/01/custom-xml-attributes-for-android-widgets/

并决定将它们发布在此处,因为官方Google“培训”文档无用且已过时(已弃用)或未涵盖我需要的内容。我希望你不介意我声称我自己的赏金,但这是我想要的解决方案(并且期望,这是我的赏金)。  我想代码必须要做;)

TextBoxOnDemand.java:

    package com.skype.widget;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.text.SpannableString;
import android.text.style.UnderlineSpan;
import android.text.util.Linkify;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnHoverListener;
import android.view.View.OnLongClickListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.ViewSwitcher;

import com.skype.ref.R;
import com.skype.ref.RemoteKeys;

public class TextBoxOnDemand extends ViewSwitcher implements OnClickListener, OnLongClickListener, OnFocusChangeListener, OnHoverListener,
        OnEditorActionListener
{
    public static final String  LOGTAG          = "TextBoxOnDemand";

    private View                btmGuard;
    private ImageButton         cancel, accept;
    private EditText            editor;
    private RelativeLayout      editorLayout;
    private TextView            face;
    private String              hint            = new String();
    private boolean             inEditMode      = false;                    //normally this is in textview mode
    private boolean             inputReady      = false;
    private String              ourData         = new String();
    private String              prefillData     = new String();
    private String              tag             = new String();         //usually tag is empty.
    private View                topGuard;
    private int                 autoLinkMask;// = Linkify.EMAIL_ADDRESSES;  //Linkify.ALL;
    private ColorStateList      textColor, hintColor = null;

    public TextBoxOnDemand(Context context)
    {
        super(context);
        build(context);
        setEditable(false); //init
    }

    public TextBoxOnDemand(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        build(context);
        init(context, attrs);
        setEditable(false); //init
    }

    public String getPrefillData()
    {
        return prefillData;
    }

    public String getTag()
    {
        return tag;
    }

    public String getText()
    {
        Log.d(LOGTAG, "getText() returning '" + ourData + "'");
        return ourData;
    }

    public boolean hasPrefillData()
    {
        return prefillData.isEmpty();
    }

    public boolean isEditable()
    {
        Log.d(LOGTAG, "isEditable() returning " + inEditMode);
        return inEditMode;
    }

    @Override
    public void onClick(View v)
    {
        Log.d(LOGTAG, "onClick(" + v + ")");
        if (inEditMode)
        {
            if (v.equals(accept))
            {
                if (editor.getEditableText().length() == 0 || editor.getEditableText().length() > 5)
                    ourData = editor.getEditableText().toString();

                setEditable(false);
            } else if (v.equals(cancel))
            {
                setEditable(false);
            }
        }
    }

    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
    {
        //      Log.d(LOGTAG, "onEditorAction(" + v + ", " + actionId + ", " + event + ") fired!");
        Log.d(LOGTAG, "onEditorAction() fired, inputReady = " + inputReady);
        if (editor.getEditableText().length() > 0 && editor.getEditableText().length() < (prefillData.length() + 2)) return true;   //the user needs to enter something


        if (inputReady && (event.getKeyCode() == RemoteKeys.ENTER.keycode() || event.getKeyCode() == KeyEvent.KEYCODE_ENTER))   //always is
        {
            if (editor.getEditableText().length() > prefillData.length() || editor.getEditableText().length() == 0)
                ourData = editor.getEditableText().toString();

            setEditable(false);
            return false;
        }

        if ((editor.getEditableText().toString().compareToIgnoreCase(ourData) == 0 || editor.getEditableText().toString()
                .compareToIgnoreCase(prefillData) == 0)
                && !inputReady) //means we didn't just keep on holding enter
            return true;
        else
            inputReady = true;

        return true;
    }

    @Override
    public void onFocusChange(View v, boolean hasFocus)
    {
        Log.d(LOGTAG, "onFocusChange(" + v + ", " + hasFocus + ")\tinEditMode = " + inEditMode);
        if (inEditMode)
        {
            if (hasFocus && (v.equals(topGuard) || v.equals(btmGuard)))
            {
                setEditable(false);
                requestFocus();
            }

            if (hasFocus && (v.equals(editor) || v.equals(accept) || v.equals(cancel)))
            {
                //do nothing, you should be able to browse freely here
                if (ourData.isEmpty() && editor.getEditableText().length() < prefillData.length())
                {
                    Log.d(LOGTAG, "adding prefill, before = " + editor.getEditableText());
                    editor.setText("");
                    editor.append(prefillData);
                    Log.d(LOGTAG, "now is = " + editor.getEditableText());
                }
            }
        } else
        {
            String text = (ourData.isEmpty()) ? hint : ourData;
            ColorStateList color;
            if (hintColor != null && ourData.isEmpty())
                color = hintColor;
            else
                color = textColor;
            face.setTextColor(color);
            if (hasFocus)
            {
                SpannableString ss = new SpannableString(text);
                ss.setSpan(new UnderlineSpan(), 0, text.length(), 0);
                face.setText(ss);
            } else
                face.setText(text);
        }
    }

    @Override
    public boolean onHover(View v, MotionEvent event)
    {
        //      Log.d(LOGTAG, "onHover()");
        String text = (ourData.isEmpty()) ? hint : ourData;
        ColorStateList color;
        if (hintColor != null && ourData.isEmpty())
            color = hintColor;
        else
            color = textColor;
        face.setTextColor(color);
        switch (event.getAction())
        {
            case MotionEvent.ACTION_HOVER_ENTER:
                SpannableString ss = new SpannableString(text);
                ss.setSpan(new UnderlineSpan(), 0, text.length(), 0);
                face.setText(ss);
                break;
            case MotionEvent.ACTION_HOVER_EXIT:
                face.setText(text);
                break;
        }
        return true;
    }

    @Override
    public boolean onLongClick(View v)
    {
        Log.d(LOGTAG, "onLongClick()\tinEditMode = " + inEditMode);
        if (!inEditMode) //implies that getDisplayedChild() == 0, meaning the textview
        {
            setEditable(true);
            return true;
        } else
            return false;
    }

    public void setEditable(boolean value)
    {
        Log.d(LOGTAG, "setEditable(" + value + ")");
        inEditMode = value;
        if (inEditMode)
        {
            //display the editorLayout
            face.setOnLongClickListener(null);
            face.setOnHoverListener(null);
            face.setOnFocusChangeListener(null);    //because of GC.
            face.setOnClickListener(null);
            face.setVisibility(View.GONE);
            setDisplayedChild(1);
            editorLayout.setVisibility(View.VISIBLE);
            editor.setOnFocusChangeListener(this);
            editor.setOnEditorActionListener(this);
            cancel.setOnClickListener(this);
            accept.setOnClickListener(this);
            accept.setOnFocusChangeListener(this);
            cancel.setOnFocusChangeListener(this);
        } else
        {
            editor.setOnFocusChangeListener(null);
            editor.setOnEditorActionListener(null);
            cancel.setOnClickListener(null);
            accept.setOnClickListener(null);
            accept.setOnFocusChangeListener(null);
            cancel.setOnFocusChangeListener(null);
            editorLayout.setVisibility(View.GONE);
            setDisplayedChild(0);
            face.setVisibility(View.VISIBLE);
            face.setOnLongClickListener(this);
            face.setOnHoverListener(this);
            face.setOnFocusChangeListener(this);
            face.setOnClickListener(this);
            face.setFocusable(true);
            face.setFocusableInTouchMode(true);
        }
        updateViews();
    }

    @Override
    public void setNextFocusDownId(int nextFocusDownId)
    {
        super.setNextFocusDownId(nextFocusDownId);
        face.setNextFocusDownId(nextFocusDownId);
        //      editor.setNextFocusDownId(nextFocusDownId);
        accept.setNextFocusDownId(nextFocusDownId);
        cancel.setNextFocusDownId(nextFocusDownId);
    }

    @Override
    public void setNextFocusForwardId(int nextFocusForwardId)
    {
        super.setNextFocusForwardId(nextFocusForwardId);
        face.setNextFocusForwardId(nextFocusForwardId);
        editor.setNextFocusForwardId(nextFocusForwardId);
    }

    @Override
    public void setNextFocusLeftId(int nextFocusLeftId)
    {
        super.setNextFocusLeftId(nextFocusLeftId);
        face.setNextFocusLeftId(nextFocusLeftId);
        editor.setNextFocusLeftId(nextFocusLeftId);
    }

    @Override
    public void setNextFocusRightId(int nextFocusRightId)
    {
        super.setNextFocusRightId(nextFocusRightId);
        face.setNextFocusRightId(nextFocusRightId);
        cancel.setNextFocusRightId(nextFocusRightId);
    }

    @Override
    public void setNextFocusUpId(int nextFocusUpId)
    {
        super.setNextFocusUpId(nextFocusUpId);
        face.setNextFocusUpId(nextFocusUpId);
        //      editor.setNextFocusUpId(nextFocusUpId);
        accept.setNextFocusUpId(nextFocusUpId);
        cancel.setNextFocusUpId(nextFocusUpId);
    }

    public void setPrefillData(String prefillData)
    {
        this.prefillData = new String(prefillData);
    }

    public String setTag()
    {
        return tag;
    }

    public void setText(String text)
    {
        Log.d(LOGTAG, "setText(" + text + ")");
        ourData = text;
        updateViews();
    }

    private void build(Context context)
    {
        Log.d(LOGTAG, "build()");
        addView(View.inflate(context, R.layout.textboxondemand, null));
        setFocusable(true);
        setFocusableInTouchMode(true);
        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
        setOnFocusChangeListener(this);
        setOnLongClickListener(this);

        face = (TextView) findViewById(R.id.TBOD_textview);
        editorLayout = (RelativeLayout) findViewById(R.id.TBOD_layout);
        editor = (EditText) findViewById(R.id.TBOD_edittext);
        accept = (ImageButton) findViewById(R.id.TBOD_accept);
        cancel = (ImageButton) findViewById(R.id.TBOD_cancel);
        topGuard = (View) findViewById(R.id.TBOD_top);
        btmGuard = (View) findViewById(R.id.TBOD_bottom);

        face.setFocusable(true);
        face.setFocusableInTouchMode(true);

        face.setOnLongClickListener(this);
        face.setOnHoverListener(this);
        face.setOnFocusChangeListener(this);
        face.setOnClickListener(this);

        editor.setOnFocusChangeListener(this);
        editor.setOnEditorActionListener(this);
        editor.setHint(hint);
        editor.setFocusable(true);
        editor.setFocusableInTouchMode(true);

        accept.setOnClickListener(this);
        accept.setOnFocusChangeListener(this);
        accept.setFocusable(true);
        cancel.setFocusable(true);
        cancel.setOnFocusChangeListener(this);
        cancel.setOnClickListener(this);

        topGuard.setFocusable(true);
        topGuard.setOnFocusChangeListener(this);
        btmGuard.setFocusable(true);
        btmGuard.setOnFocusChangeListener(this);

        editor.setNextFocusRightId(R.id.TBOD_accept);
        editor.setNextFocusDownId(R.id.TBOD_bottom);
        editor.setNextFocusUpId(R.id.TBOD_top);

        accept.setNextFocusLeftId(R.id.TBOD_edittext);
        accept.setNextFocusRightId(R.id.TBOD_cancel);
        cancel.setNextFocusLeftId(R.id.TBOD_accept);
    }

    private void init(Context context, AttributeSet attrs)
    {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextBoxOnDemand);
        //Use a
        Log.d(LOGTAG, "init()");
        if (a == null) Log.d(LOGTAG, "Did you include 'xmlns:app=\"http://schemas.android.com/apk/res-auto\"' in your root layout?");

        final int N = a.getIndexCount();
        for (int i = 0; i < N; ++i)
        {
            int attr = a.getIndex(i);
            switch (attr)
            {
                case R.styleable.TextBoxOnDemand_android_hint:
                    hint = new String(a.getString(attr));
                    editor.setHint(a.getString(attr));
                    break;
                case R.styleable.TextBoxOnDemand_android_text:
                    ourData = new String(a.getString(attr));
                    break;
                case R.styleable.TextBoxOnDemand_android_inputType:
                    int inputType = a.getInt(attr, -1);
                    if (inputType != -1) editor.setInputType(inputType);
                    break;
                case R.styleable.TextBoxOnDemand_android_textColor:
                    textColor = a.getColorStateList(attr);
                    face.setTextColor(textColor);
                    break;
                case R.styleable.TextBoxOnDemand_android_linksClickable:
                    face.setLinksClickable(a.getBoolean(attr, true));
                    break;
                case R.styleable.TextBoxOnDemand_android_textColorHint:
                    hintColor = a.getColorStateList(attr);
                    break;
                case R.styleable.TextBoxOnDemand_android_autoLink:
                    autoLinkMask = a.getInt(attr, 0);
                    face.setAutoLinkMask(autoLinkMask);
                    break;

                default:
                    Log.d(LOGTAG, "Skipping attribute " + attr);
            }
        }

        //Don't forget this
        a.recycle();
    }

    private void updateViews()
    {
        Log.d(LOGTAG, "updateViews()");
        //      if (getDisplayedChild() == 0)   //first child - textview
        if (!inEditMode)    //first child - textview
        {
            if (ourData.isEmpty())
            {
                if (hintColor != null) face.setTextColor(hintColor);
                face.setText(hint);
            } else
            {
                face.setTextColor(textColor);
                face.setText(ourData);
            }
            face.setFocusable(true);
            face.setFocusableInTouchMode(true);
            face.setAutoLinkMask(autoLinkMask);
        } else
        {   //second child - edittext
            editor.setFocusable(true);
            editor.setFocusableInTouchMode(true);
            if (ourData.startsWith(prefillData) || ourData.length() >= prefillData.length())
                editor.setText("");
            else
                editor.setText(prefillData);

            editor.append(ourData);
            inputReady = false;

            editor.requestFocus();
        }
    }

    public void setAutoLinkMask(LinkifyEnum linkifyEnumConstant)
    {
        switch (linkifyEnumConstant)
        {
            case ALL:
                autoLinkMask = Linkify.ALL;
                break;
            case EMAIL_ADDRESSES:
                autoLinkMask = Linkify.EMAIL_ADDRESSES;
                break;
            case MAP_ADDRESSES:
                autoLinkMask = Linkify.MAP_ADDRESSES;
                break;
            case PHONE_NUMBERS:
                autoLinkMask = Linkify.PHONE_NUMBERS;
                break;
            case WEB_URLS:
                autoLinkMask = Linkify.WEB_URLS;
                break;

            case NONE:
            default:
                autoLinkMask = 0;
                break;
        }
        //set it now
        face.setAutoLinkMask(autoLinkMask);
    }

    public enum LinkifyEnum
    {
        ALL, EMAIL_ADDRESSES, MAP_ADDRESSES, PHONE_NUMBERS, WEB_URLS, NONE
    };

}

我仍在研究一些与焦点相关的问题,但这是按预期工作的。当我使用onFocuslistener 1时,你无法从一个TextBox聚焦到另一个TextBox;当文本框本身是可聚焦的时候,我可以从一个聚焦到另一个就好了,但是我无法通过孩子进行相互聚焦,因此无法专注于要输入的edittext。

XML文件:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/TBOD_textview"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:autoLink="email"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:linksClickable="true"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <RelativeLayout
        android:id="@+id/TBOD_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <EditText
            android:id="@+id/TBOD_edittext"
            android:layout_width="300dp"
            android:layout_height="30dp"
            android:layout_below="@+id/TBOD_textview"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:imeOptions="actionDone"
            android:inputType="none"
            android:maxLines="1"
            android:padding="2dp"
            android:singleLine="true"
            android:textColor="@android:color/black"
            android:textSize="14dp" />

        <ImageButton
            android:id="@+id/TBOD_accept"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/TBOD_edittext"
            android:layout_marginLeft="15dp"
            android:layout_toRightOf="@+id/TBOD_edittext"
            android:background="@drawable/button_accept_selector" />

        <ImageButton
            android:id="@+id/TBOD_cancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/TBOD_edittext"
            android:layout_marginLeft="5dp"
            android:layout_toRightOf="@+id/TBOD_accept"
            android:background="@drawable/button_cancel_selector" />

        <View
            android:id="@+id/TBOD_top"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_alignParentTop="true"
            android:background="@android:color/transparent" />

        <View
            android:id="@+id/TBOD_bottom"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_alignParentBottom="true"
            android:background="@android:color/transparent" />
    </RelativeLayout>

</RelativeLayout>

最后是attrs.xml文件:

 <?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="TextBoxOnDemand">
        <attr name="android:text" />
        <attr name="android:inputType" />
        <attr name="android:hint" />
        <attr name="android:textColor" />
        <attr name="android:textColorHint" />
        <attr name="android:linksClickable" />
        <attr name="android:autoLink" />
    </declare-styleable>

</resources>

这是我在我的主xml中使用它的方式(在包含所需的命名空间添加之后):

 <com.shark.widget.TextBoxOnDemand
    android:id="@+id/profile_email2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/profile_skypename"
    android:layout_below="@+id/profile_email_placeholder"
    android:hint="@string/add_email"
    android:inputType="textEmailAddress"
    android:textColor="@android:color/white"
    android:textColorHint="@color/skype_blue" />
编辑:我调试了焦点问题。事实证明,除非你致电

,否则很难把重点放在孩子身上
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);

哪种方法可以解决问题,但仍然无法解决问题。经过一段时间与onFocusChange()听众仍然试图获得完美行为的游戏,我扔了毛巾,并添加了两个焦点警卫。我意识到我无法仅仅在我的容器上跟踪失去焦点(由于它从未接收到焦点)但我不妨跟踪想要离开编辑区域的想法...所以我走了肮脏的路线并添加了两个看不见的条状视图,以打开两者之间的编辑文本。一旦他们获得了焦点,我就可以隐藏组件并确保它们正常转换。

就是这样,现在它可以正常工作。感谢所有参与者。

EDIT3:最终抛光版本,我倾倒了自定义标签,因为它们根本无法正常工作。需要学习的经验:如果某个东西有一个android标签,请不要打扰它。