问题描述
我想有一个TextView显示文字,当你点击它/ longclick,一个文本框应该现身,并允许上述文字编辑。当你完成编辑(安其进入我想)应该恢复与更新的文字一个TextView ...
我不知道,如果是feasable实现这样的小部件,或者我应该砍一个解决方法吗?提示和建议都非常欢迎。
如果你需要我的意思进一步的想法,就到你如(视窗)的Skype个人资料,并看到自己。
编辑:
澄清:我专门要求Widget或这样这是一个TextView,直到点击,然后转变为含有相同的文字一个EditText;一旦完成编辑将其转换回一个TextView重新presenting新的改变的文本。这就是我所说的按需部件的EditText。
但我希望能得到更好的东西比
公共类的Widget {
TextView的文本;
编辑的EditText;
字符串textToRe present;
// ...
}
就像我上周四表示...尤伯是pretty接近,但不是很密切。他确实有个大致相同的想法,但(理论上)冲进code太早;)
下面列出的TextBoxOnDemand code是生产就绪。这个想法是相似,我想避免的OP和尤伯什么建议,但最佳实现(使用而不是为实例的RelativeLayout的一个ViewSwitcher)
我收集为此所需资源,在下面的文章:
自定义视图
Declaring一个定制的Android使用的UI元素XML
How通过在Java和XML 的自定义组件的参数
和决定张贴在这里,因为谷歌官方培训文档是无用的,要么是过时的(de precated)或不包括我需要的东西。我希望你不介意我称我自己的奖金,但是这是我想要的解决方案(和预期,ERGO赏金)。
我猜code将不得不这样做;)
TextBoxOnDemand.java:
包com.skype.widget;进口android.content.Context;
进口android.content.res.ColorStateList;
进口android.content.res.TypedArray;
进口android.text.SpannableString;
进口android.text.style.UnderlineSpan;
进口android.text.util.Linkify;
进口android.util.AttributeSet;
进口android.util.Log;
进口android.view.KeyEvent;
进口android.view.MotionEvent;
进口android.view.View;
进口android.view.View.OnClickListener;
进口android.view.View.OnFocusChangeListener;
进口android.view.View.OnHoverListener;
进口android.view.View.OnLongClickListener;
进口android.widget.EditText;
进口android.widget.ImageButton;
进口android.widget.RelativeLayout;
进口android.widget.TextView;
进口android.widget.TextView.OnEditorActionListener;
进口android.widget.ViewSwitcher;进口com.skype.ref.R;
进口com.skype.ref.RemoteKeys;公共类TextBoxOnDemand扩展ViewSwitcher实现OnClickListener,OnLongClickListener,OnFocusChangeListener,OnHoverListener,
OnEditorActionListener
{
公共静态最后弦乐LOGTAG =TextBoxOnDemand; 私人查看btmGuard;
私人的ImageButton取消,接受;
私人的EditText编辑;
私人的RelativeLayout editorLayout;
私人TextView的脸;
私人字符串提示=新的String();
私人布尔inEditMode = FALSE; //通常这是TextView的模式
私人布尔inputReady = FALSE;
私人字符串ourData =新的String();
私人字符串prefillData =新的String();
私人字符串标记=新的String(); //通常标记为空。
私人查看topGuard;
私人诠释autoLinkMask; // = Linkify.EMAIL_ADDRESSES; //Linkify.ALL;
私人ColorStateList文字颜色,hintColor = NULL; 公共TextBoxOnDemand(上下文的背景下)
{
超级(上下文);
建立(上下文);
setEditable(假); //在里面
} 公共TextBoxOnDemand(上下文的背景下,ATTRS的AttributeSet)
{
超(背景下,ATTRS);
建立(上下文);
的init(背景下,ATTRS);
setEditable(假); //在里面
} 公共字符串的get prefillData()
{
返回prefillData;
} 公共字符串getTag()
{
返回标签;
} 公共字符串的getText()
{
Log.d(LOGTAG的getText()返回'+ ourData +');
返回ourData;
} 公共布尔有prefillData()
{
返回prefillData.isEmpty();
} 公共布尔isEditable()
{
Log.d(LOGTAGisEditable()返回+ inEditMode);
返回inEditMode;
} @覆盖
公共无效的onClick(视图v)
{
Log.d(LOGTAG的onClick(+ V +));
如果(inEditMode)
{
如果(v.equals(接受))
{
如果(editor.getEditableText()长度()== 0 || editor.getEditableText()长度()方式> 5)
。ourData = editor.getEditableText()的toString(); setEditable(假);
}否则如果(v.equals(取消))
{
setEditable(假);
}
}
} @覆盖
公共布尔onEditorAction(TextView的V,INT actionId,KeyEvent的事件)
{
// Log.d(LOGTAGonEditorAction(+ V +,+ actionId +,+事件+)被解雇了!);
Log.d(LOGTAGonEditorAction()解雇,inputReady =+ inputReady);
如果(editor.getEditableText()长()方式> 0安培;&安培; editor.getEditableText()长()<(prefillData.length()+ 2))返回true; //用户需要输入一些
如果(inputReady&安培;及(event.getKey code()== RemoteKeys.ENTER.key code()|| event.getKey code()== KeyEvent.KEY code_ENTER ))//总是
{
如果(editor.getEditableText()长()方式> prefillData.length()|| editor.getEditableText()长()== 0)
。ourData = editor.getEditableText()的toString(); setEditable(假);
返回false;
} 如果((editor.getEditableText()。toString()方法。与compareToIgnoreCase(ourData)== 0 || editor.getEditableText()。的toString()
.compareToIgnoreCase(prefillData)== 0)
&功放;&安培; !inputReady)//意味着我们不只是继续持有进入
返回true;
其他
inputReady = TRUE; 返回true;
} @覆盖
公共无效onFocusChange(视图V,布尔hasFocus)
{
Log.d(LOGTAGonFocusChange(+ V +,+ hasFocus +)\\ tinEditMode =+ inEditMode);
如果(inEditMode)
{
如果(hasFocus&放大器;及(v.equals(topGuard)|| v.equals(btmGuard)))
{
setEditable(假);
requestFocus()方法;
} 如果(hasFocus&放大器;及(v.equals(编辑)|| v.equals(接受)|| v.equals(取消)))
{
//什么也不做,你应该能够自由地在这里浏览
如果(ourData.isEmpty()及&放大器; editor.getEditableText()长度()&所述; prefillData.length())
{
Log.d(LOGTAG,并称pre灌注,在此之前=+ editor.getEditableText());
editor.setText();
editor.append(prefillData);
Log.d(LOGTAG,现在是=+ editor.getEditableText());
}
}
}其他
{
字符串文本=(ourData.isEmpty())?提示:ourData;
ColorStateList色;
如果(hintColor = NULL&放大器;!&安培; ourData.isEmpty())
颜色= hintColor;
其他
颜色=文字颜色;
face.setTextColor(颜色);
如果(hasFocus)
{
SpannableString SS =新SpannableString(文本);
ss.setSpan(新UnderlineSpan(),0,text.length(),0);
face.setText(SS);
}其他
face.setText(文本);
}
} @覆盖
公共布尔onHover(视图V,MotionEvent事件)
{
// Log.d(LOGTAGonHover());
字符串文本=(ourData.isEmpty())?提示:ourData;
ColorStateList色;
如果(hintColor = NULL&放大器;!&安培; ourData.isEmpty())
颜色= hintColor;
其他
颜色=文字颜色;
face.setTextColor(颜色);
开关(event.getAction())
{
案例MotionEvent.ACTION_HOVER_ENTER:
SpannableString SS =新SpannableString(文本);
ss.setSpan(新UnderlineSpan(),0,text.length(),0);
face.setText(SS);
打破;
案例MotionEvent.ACTION_HOVER_EXIT:
face.setText(文本);
打破;
}
返回true;
} @覆盖
公共布尔onLongClick(视图V)
{
Log.d(LOGTAGonLongClick()\\ tinEditMode =+ inEditMode);
如果(!inEditMode)//意味着getDisplayedChild()== 0,表示的TextView
{
setEditable(真);
返回true;
}其他
返回false;
} 公共无效setEditable(布尔值)
{
Log.d(LOGTAGsetEditable(+值+));
inEditMode =价值;
如果(inEditMode)
{
//显示editorLayout
face.setOnLongClickListener(NULL);
face.setOnHoverListener(NULL);
face.setOnFocusChangeListener(NULL); //因为GC的。
face.setOnClickListener(NULL);
face.setVisibility(View.GONE);
setDisplayedChild(1);
editorLayout.setVisibility(View.VISIBLE);
editor.setOnFocusChangeListener(本);
editor.setOnEditorActionListener(本);
cancel.setOnClickListener(本);
accept.setOnClickListener(本);
accept.setOnFocusChangeListener(本);
cancel.setOnFocusChangeListener(本);
}其他
{
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(本);
face.setOnHoverListener(本);
face.setOnFocusChangeListener(本);
face.setOnClickListener(本);
face.setFocusable(真);
face.setFocusableInTouchMode(真);
}
updateViews();
} @覆盖
公共无效setNextFocusDownId(INT nextFocusDownId)
{
super.setNextFocusDownId(nextFocusDownId);
face.setNextFocusDownId(nextFocusDownId);
// editor.setNextFocusDownId(nextFocusDownId);
accept.setNextFocusDownId(nextFocusDownId);
cancel.setNextFocusDownId(nextFocusDownId);
} @覆盖
公共无效setNextFocusForwardId(INT nextFocusForwardId)
{
super.setNextFocusForwardId(nextFocusForwardId);
face.setNextFocusForwardId(nextFocusForwardId);
editor.setNextFocusForwardId(nextFocusForwardId);
} @覆盖
公共无效setNextFocusLeftId(INT nextFocusLeftId)
{
super.setNextFocusLeftId(nextFocusLeftId);
face.setNextFocusLeftId(nextFocusLeftId);
editor.setNextFocusLeftId(nextFocusLeftId);
} @覆盖
公共无效setNextFocusRightId(INT nextFocusRightId)
{
super.setNextFocusRightId(nextFocusRightId);
face.setNextFocusRightId(nextFocusRightId);
cancel.setNextFocusRightId(nextFocusRightId);
} @覆盖
公共无效setNextFocusUpId(INT nextFocusUpId)
{
super.setNextFocusUpId(nextFocusUpId);
face.setNextFocusUpId(nextFocusUpId);
// editor.setNextFocusUpId(nextFocusUpId);
accept.setNextFocusUpId(nextFocusUpId);
cancel.setNextFocusUpId(nextFocusUpId);
} 公共无效集prefillData(字符串prefillData)
{
这prefillData =新的String(prefillData);
} 公共字符串setTag()
{
返回标签;
} 公共无效的setText(字符串文本)
{
Log.d(LOGTAG的setText(+文字+));
ourData =文本;
updateViews();
} 私人无效版本(上下文的背景下)
{
Log.d(LOGTAG,建立());
addView(View.inflate(背景下,R.layout.textboxondemand,NULL));
setFocusable(真);
setFocusableInTouchMode(真);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setOnFocusChangeListener(本);
setOnLongClickListener(本); FACE =(的TextView)findViewById(R.id.TBOD_textview);
editorLayout =(RelativeLayout的)findViewById(R.id.TBOD_layout);
编辑=(EditText上)findViewById(R.id.TBOD_edittext);
接受=(的ImageButton)findViewById(R.id.TBOD_accept);
取消=(的ImageButton)findViewById(R.id.TBOD_cancel);
topGuard =(查看)findViewById(R.id.TBOD_top);
btmGuard =(查看)findViewById(R.id.TBOD_bottom); face.setFocusable(真);
face.setFocusableInTouchMode(真); face.setOnLongClickListener(本);
face.setOnHoverListener(本);
face.setOnFocusChangeListener(本);
face.setOnClickListener(本); editor.setOnFocusChangeListener(本);
editor.setOnEditorActionListener(本);
editor.setHint(提示);
editor.setFocusable(真);
editor.setFocusableInTouchMode(真); accept.setOnClickListener(本);
accept.setOnFocusChangeListener(本);
accept.setFocusable(真);
cancel.setFocusable(真);
cancel.setOnFocusChangeListener(本);
cancel.setOnClickListener(本); topGuard.setFocusable(真);
topGuard.setOnFocusChangeListener(本);
btmGuard.setFocusable(真);
btmGuard.setOnFocusChangeListener(本); 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);
} 私人无效的init(上下文的背景下,ATTRS的AttributeSet)
{
TypedArray A = context.obtainStyledAttributes(ATTRS,R.styleable.TextBoxOnDemand);
//用一个
Log.d(LOGTAG的init());
如果(A == NULL)Log.d(LOGTAG,你有'的xmlns:程序= \\HTTP://schemas.android.com/apk/res-auto \\'?在你的根布局); 最终诠释N = a.getIndexCount();
的for(int i = 0; I< N ++ I)
{
INT ATTR = a.getIndex(ⅰ);
开关(ATTR)
{
案例R.styleable.TextBoxOnDemand_android_hint:
提示=新的String(a.getString(attr)使用);
editor.setHint(a.getString(attr)使用);
打破;
案例R.styleable.TextBoxOnDemand_android_text:
ourData =新的String(a.getString(attr)使用);
打破;
案例R.styleable.TextBoxOnDemand_android_inputType:
INT的inputType = a.getInt(ATTR,-1);
如果(!inputType下= -1)editor.setInputType(inputType下);
打破;
案例R.styleable.TextBoxOnDemand_android_textColor:
文字颜色= a.getColorStateList(attr)使用;
face.setTextColor(文字颜色);
打破;
案例R.styleable.TextBoxOnDemand_android_linksClickable:
face.setLinksClickable(a.getBoolean(ATTR,真实));
打破;
案例R.styleable.TextBoxOnDemand_android_textColorHint:
hintColor = a.getColorStateList(attr)使用;
打破;
案例R.styleable.TextBoxOnDemand_android_autoLink:
autoLinkMask = a.getInt(ATTR,0);
face.setAutoLinkMask(autoLinkMask);
打破; 默认:
Log.d(LOGTAG,跳绳属性+ attr)使用;
}
} //不要忘记这一点
a.recycle();
} 私人无效updateViews()
{
Log.d(LOGTAGupdateViews());
//如果(getDisplayedChild()== 0)//第一个孩子 - 的TextView
如果(inEditMode!)//第一个孩子 - 的TextView
{
如果(ourData.isEmpty())
{
如果(hintColor!= NULL)face.setTextColor(hintColor);
face.setText(提示);
}其他
{
face.setTextColor(文字颜色);
face.setText(ourData);
}
face.setFocusable(真);
face.setFocusableInTouchMode(真);
face.setAutoLinkMask(autoLinkMask);
}其他
{//第二个孩子 - 的EditText
editor.setFocusable(真);
editor.setFocusableInTouchMode(真);
如果(ourData.startsWith(prefillData)|| ourData.length()> = prefillData.length())
editor.setText();
其他
editor.setText(prefillData); editor.append(ourData);
inputReady = FALSE; editor.requestFocus();
}
} 公共无效setAutoLinkMask(LinkifyEnum linkifyEnumConstant)
{
开关(linkifyEnumConstant)
{
情况下,所有:
autoLinkMask = Linkify.ALL;
打破;
案例EMAIL_ADDRESSES:
autoLinkMask = Linkify.EMAIL_ADDRESSES;
打破;
案例MAP_ADDRESSES:
autoLinkMask = Linkify.MAP_ADDRESSES;
打破;
案例PHONE_NUMBERS:
autoLinkMask = Linkify.PHONE_NUMBERS;
打破;
案例WEB_URLS:
autoLinkMask = Linkify.WEB_URLS;
打破; 案例NONE:
默认:
autoLinkMask = 0;
打破;
}
//现在设置
face.setAutoLinkMask(autoLinkMask);
} 公共枚举LinkifyEnum
{
ALL,EMAIL_ADDRESSES,MAP_ADDRESSES,PHONE_NUMBERS,WEB_URLS,NONE
};}
我还在一些重点相关的问题,但这个工程按预期。当我使用onFocuslistener 1,你不能从关注一个TextBox之分;当文本框本身是可聚焦,我可以集中精力从一个到另一个就好了,但我不能跨重点纯洁了孩子,因此无法集中的EditText键入
XML文件:
<的RelativeLayout的xmlns:机器人=http://schemas.android.com/apk/res/android
机器人:layout_width =WRAP_CONTENT
机器人:layout_height =WRAP_CONTENT> <的TextView
机器人:ID =@ + ID / TBOD_textview
机器人:layout_width =WRAP_CONTENT
机器人:layout_height =FILL_PARENT
机器人:自动链接=电子邮件
机器人:可聚焦=真
机器人:focusableInTouchMode =真
机器人:linksClickable =真
机器人:textAppearance =机器人:ATTR / textAppearanceMedium/> < RelativeLayout的
机器人:ID =@ + ID / TBOD_layout
机器人:layout_width =WRAP_CONTENT
机器人:layout_height =WRAP_CONTENT> <的EditText
机器人:ID =@ + ID / TBOD_edittext
机器人:layout_width =300dp
机器人:layout_height =30dp
机器人:layout_below =@ + ID / TBOD_textview
机器人:可聚焦=真
机器人:focusableInTouchMode =真
机器人:imeOptions =actionDone
安卓的inputType =无
机器人:MAXLINES =1
机器人:填充=2DP
机器人:单线=真
机器人:文字颜色=@机器人:彩色/黑白
机器人:TEXTSIZE =14dp/> <的ImageButton
机器人:ID =@ + ID / TBOD_accept
机器人:layout_width =WRAP_CONTENT
机器人:layout_height =WRAP_CONTENT
机器人:layout_alignTop =@ + ID / TBOD_edittext
机器人:layout_marginLeft =15dp
机器人:layout_toRightOf =@ + ID / TBOD_edittext
机器人:背景=@绘制/ button_accept_selector/> <的ImageButton
机器人:ID =@ + ID / TBOD_cancel
机器人:layout_width =WRAP_CONTENT
机器人:layout_height =WRAP_CONTENT
机器人:layout_alignTop =@ + ID / TBOD_edittext
机器人:layout_marginLeft =5DP
机器人:layout_toRightOf =@ + ID / TBOD_accept
机器人:背景=@绘制/ button_cancel_selector/> <查看
机器人:ID =@ + ID / TBOD_top
机器人:layout_width =FILL_PARENT
机器人:layout_height =0dp
机器人:layout_alignParentTop =真
机器人:背景=@机器人:彩色/透明/> <查看
机器人:ID =@ + ID / TBOD_bottom
机器人:layout_width =FILL_PARENT
机器人:layout_height =0dp
机器人:layout_alignParentBottom =真
机器人:背景=@机器人:彩色/透明/>
< / RelativeLayout的>< / RelativeLayout的>
和最后,attrs.xml文件:
<?XML版本=1.0编码=UTF-8&GT?;
<资源> <申报-设置样式名称=TextBoxOnDemand>
< attr指示名=机器人:文字/>
< attr指示名=机器人:inputType下/>
< attr指示名=机器人:提示/>
< attr指示名=机器人:文字颜色/>
< attr指示名=机器人:textColorHint/>
< attr指示名=机器人:linksClickable/>
< attr指示名=机器人:自动链接/>
< /申报,设置样式>< /资源>
这是我用它在我的主XML(包括所需的名称空间中添加后):
< com.shark.widget.TextBoxOnDemand
机器人:ID =@ + ID / profile_email2
机器人:layout_width =WRAP_CONTENT
机器人:layout_height =WRAP_CONTENT
机器人:layout_alignLeft =@ + ID / profile_skypename
机器人:layout_below =@ + ID / profile_email_placeholder
机器人:提示=@字符串/ add_email
安卓的inputType =textEmailAddress
机器人:文字颜色=@机器人:彩色/白
机器人:textColorHint =@色/ skype_blue/>
编辑:我调试的焦点问题。事实证明,给予重点孩子很难,除非你叫
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
这有点儿补救这个问题,但仍然没有解决。一些而玩弄的 onFocusChange()
监听器仍试图获得完美的表现后,我认输,放入加了两个重点看守。我意识到,我无法跟踪对焦的损失只在我的容器(由于它永远不会获得焦点),但我还不如追踪想从编辑字段移开的想法...让我去脏的路线,增加了两个隐形条状意见sandwitch中的EditText之间。一旦他们得到了关注的焦点,我可以隐藏组件,并确保它们正常过渡。
和那里的是,现在它的作品,因为它应该。感谢所有谁参加。
EDIT3:最后的打磨版本,我甩了自定义标签,因为他们根本就没有足够可靠工作。忠告就是:如果有东西的机器人标签,不要打扰它克隆
I'd like to have a TextView display text, and when you click/longclick on it, a textbox should "show up" and allow editing of said text. When you're done editing (onkey enter i suppose) it should revert back to a textview with the updated text...
I'm wondering if it's feasable to implement such a widget or should I hack a workaround? Tips and suggestions are very welcome.
If you need further idea of what I mean, just go to your e.g. (windows) skype profile and see for yourself.
EDIT:Clarification: I'm specifically asking for a widget or such which is a textview until clicked on, then transforms to an edittext containing the same text; once done editing it transforms back to a textview representing the new changed text. Thats what i mean by "edittext on demand widget".
But I'm hoping to get something better than
public class Widget {
TextView text;
EditText edit;
String textToRepresent;
//...
}
Like I said on thursday... Yul was pretty close but not quite close. He did have a general same idea but (theoretically) rushed into code too early ;)
The TextBoxOnDemand code supplied below is production-ready. The idea is similar to what I wanted to avoid in the OP and what Yul suggested, but with optimal implementation (using a ViewSwitcher instead of a RelativeLayout for instance)
I gathered the resources needed for this in the following articles:
Declaring a custom android UI element using XML
How to pass custom component parameters in java and xml
http://kevindion.com/2011/01/custom-xml-attributes-for-android-widgets/
and decided to post them here because the official Google "training" docs are useless and are either obsolete (deprecated) or do not cover what I needed. I hope you don't mind me claiming my own bounty, but this is the solution I wanted (and expected, ergo the bounty). I guess the code will have to do ;)
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
};
}
I'm still working out some focus-related issues but this works as intended. When I use onFocuslistener 1, you can't focus from one TextBox to the other; when the textbox itself is focusable, I can focus from one to the other just fine, but I cannot inter-focus thru children and thus can't focus on the edittext to type.
the XML file:
<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>
and finally, the attrs.xml file:
<?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>
This is how I used it in my main xml (after including the required namespace add):
<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" />
EDIT: I've debugged the focus issues. It turns out that giving focus to children is difficult unless you call
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
Which kinda remedies the issue but still doesn't solve it. After some while of playing around with the onFocusChange()
listener still trying to get the perfect behaviour, I threw in the towel and put in added two focus guards. I realized I cannot track the loss of focus only on my container (due to it never receiving focus) but I might as well track the idea of wanting to move away from the edit field... So i went the dirty route and added two invisible bar-like views to sandwitch the edittext in between. Once they got the focus, I could hide the component and ensure they transition properly.
And there it is, now it works as it should. Thanks to all who participated.
EDIT3: final polished version, i dumped the custom tags because they simply don't work reliably enough. Lesson to be learned: if there is an android tag for something, don't bother cloning it.
这篇关于EditText上点播插件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!