1

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

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

如果您需要进一步了解我的意思,只需转到您的例如(Windows)Skype 配置文件并亲自查看。

编辑:澄清:我特别要求一个小部件等,它是一个文本视图,直到被点击,然后转换为一个包含相同文本的编辑文本;一旦完成编辑,它就会转换回代表新更改文本的文本视图。这就是我所说的“按需编辑文本小部件”的意思。

但我希望能得到比

public class Widget {
     TextView text;
     EditText edit;
     String   textToRepresent;
     //...
}
4

4 回答 4

4

您在这里有几个不同的选择。

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

然后让你的 onClick 函数启动一个DialogFragment。我喜欢创建显示功能。请注意,您可以使用此处的支持库来使您的应用向后兼容。

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

DialogFragment 非常简单。在您的 onCreateView 中,您将膨胀您想要向用户显示的视图。如果您不想自定义,也可以使用简单的AlertDialogBu​​ilder包装它。

@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

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

然后您可以startActivityForResult显示您的对话框,然后在onActivityResult中捕获您的结果

于 2012-08-09T15:45:04.650 回答
2

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

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:我忘了。您应该为您的文本视图添加一些underline格式,以使用户注意到它可点击

于 2012-08-09T16:22:07.393 回答
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>
于 2012-08-10T18:35:43.360 回答
0

就像我在星期四说的那样……尤尔非常接近,但不是很接近。他确实有一个大致相同的想法,但(理论上)过早地冲进代码;)

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

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

从 xml 创建自定义视图

使用 XML 声明一个自定义的 android UI 元素

定义自定义属性

如何在 java 和 xml 中传递自定义组件参数

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

并决定在这里发布它们,因为官方的谷歌“培训”文档是无用的,要么已经过时(不推荐),要么没有涵盖我需要的内容。我希望你不介意我声称自己的赏金,但这是我想要的解决方案(并且预期,因此赏金)。我想代码将不得不这样做;)

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 聚焦到另一个;当文本框本身可聚焦时,我可以从一个聚焦到另一个聚焦,但我不能通过孩子相互聚焦,因此不能专注于要输入的编辑文本。

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 标签,不要费心去克隆它。

于 2012-08-13T17:04:29.217 回答