Это было просто зафиксировано в материальных компонентах для lib Android, см.: https://github.com/material-components/material-components-android/pull/358
Я основывал свое решение на FixedTextInputEditText
, как упомянуто в https://github.com/android-in-china/Compatibility/issues/11#issuecomment-427560370.
Прежде всего все я создал фиксированное TextInputEditText
экземпляр:
public class MeizuTextInputEditText extends TextInputEditText {
public MeizuTextInputEditText(Context context) {
super(context);
}
public MeizuTextInputEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MeizuTextInputEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public CharSequence getHint() {
try {
return getMeizuHintHack();
} catch (Exception e) {
return super.getHint();
}
}
private CharSequence getMeizuHintHack() throws NoSuchFieldException, IllegalAccessException {
Field textView = TextView.class.getDeclaredField("mHint");
textView.setAccessible(true);
return (CharSequence) textView.get(this);
}
}
, Но затем я должен был бы заменить весь мой TextInputEditText
использования с MeizuTextInputEditText
, который не является чем-то, что можно легко сделать на большей кодовой базе. Также, когда создание будущего просматривает Вас, всегда должен рассматривать использование MeizuTextInputEditText
вместо 'поврежденного'. Упущение об этом легко представило бы производственные проблемы снова.
, Таким образом, заключительная фиксация состоит из пользовательского класса представления и вместе с библиотекой ViewPump ( https://github.com/InflationX/ViewPump), мы можем легко сделать это. Столь же объясненный в документах необходимо зарегистрировать пользовательский перехватчик, который похож на этого:
public class TextInputEditTextInterceptor implements Interceptor {
@Override
public InflateResult intercept(Chain chain) {
InflateRequest request = chain.request();
View view = inflateView(request.name(), request.context(), request.attrs());
if (view != null) {
return InflateResult.builder()
.view(view)
.name(view.getClass().getName())
.context(request.context())
.attrs(request.attrs())
.build();
} else {
return chain.proceed(request);
}
}
@Nullable
private View inflateView(String name, Context context, AttributeSet attrs) {
if (name.endsWith("TextInputEditText")) {
return new MeizuTextInputEditText(context, attrs);
}
return null;
}
}
И регистрация, что пользовательский перехватчик сделан так же, как в документах путем установки ViewPump на onCreate действия:
@Override
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewPump.Builder viewPumpBuilder = ViewPump.builder();
if (isMeizuDevice()) {
viewPumpBuilder.addInterceptor(new TextInputEditTextInterceptor());
}
ViewPump.init(viewPumpBuilder.build());
}
, Как Вы видите, я только расширяюсь MeizuTextInputEditText
, если устройство Meizu обнаруживается. Тем путем отражение не инициировано для устройств, которым не нужно оно. Также этот метод является основным классом Действия, который я имею, от которого любое действие расширяется в моем проекте так каждое действие, которое запускается в моем проекте И где устройством является Meizu, будет иметь фиксацию автоматически!
Я использую Kotlin и Fragments и меня просто рекурсивно устраняющий все вводы текста в onViewCreated.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
fixTextInputEditText(view) // call this in onViewCreated
}
private fun fixTextInputEditText(view: View) {
val manufacturer = Build.MANUFACTURER.toUpperCase(Locale.US)
if ("MEIZU" in manufacturer) {
val views = getAllTextInputs(view)
views.forEach(::hackFixHintsForMeizu)
}
}
private fun getAllTextInputs(v: View): List<TextInputEditText> {
if (v !is ViewGroup) {
val editTexts = mutableListOf<TextInputEditText>()
(v as? TextInputEditText)?.let {
editTexts += it
}
return editTexts
}
val result = mutableListOf<TextInputEditText>()
for (i in 0 until v.childCount) {
val child = v.getChildAt(i)
result += getAllTextInputs(child)
}
return result
}
private fun hackFixHintsForMeizu(editText: TextInputEditText) {
if (editText.hint != null) {
editText.setHintTextColor(Color.TRANSPARENT)
editText.hint = editText.hint
}
}
Эта фиксация теперь включена в новый выпуск материальных компонентов здесь: https://github.com/material-components/material-components-android/releases/tag/1.1.0-alpha09
Ни один из вариантов выше обработанного для меня без модификаций.
Мое приложение использует фрагменты, TextInputEditText, иногда используясь без TextInputLayout, обновляя до последнего AndroidX не был опцией в это время, заменение TextInputEditText было также не опцией в это время.
Моя версия (на основе тех решение и фиксация Google):
import android.os.Build
import java.util.*
import android.content.Context
import android.support.design.widget.TextInputEditText
import android.util.AttributeSet
import android.widget.TextView
import android.support.design.widget.TextInputLayout
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import java.lang.reflect.Field
import java.lang.reflect.Method
import android.support.design.R
class MyInputEditText(context: Context?, attrs: AttributeSet?,defStyleAttr:Int) : TextInputEditText(context, attrs,defStyleAttr){
constructor(context: Context?, attrs: AttributeSet?):this(context,attrs,R.attr.editTextStyle)
constructor(context: Context?):this(context,null,R.attr.editTextStyle)
private val buggyMeizu = ("meizu") in Build.MANUFACTURER.toLowerCase(Locale.US)
private lateinit var getTextInputLayoutMethod:Method
private lateinit var providesHintMethod:Method
private lateinit var mHintField:Field
init {
if (buggyMeizu) {
getTextInputLayoutMethod=TextInputEditText::class.java.getDeclaredMethod("getTextInputLayout")
getTextInputLayoutMethod.isAccessible=true
providesHintMethod=TextInputLayout::class.java.getDeclaredMethod("isProvidingHint")
providesHintMethod.isAccessible=true
mHintField=TextView::class.java.getDeclaredField("mHint")
mHintField.isAccessible=true
}
}
private fun getTILProvidesHint():Boolean {
val layout=getTIL()
if (layout!=null) {
val result=providesHintMethod.invoke(layout) as Boolean
return result;
} else {
return false
}
}
private fun getTIL():TextInputLayout? = getTextInputLayoutMethod.invoke(this) as TextInputLayout?
private fun getBaseHint():CharSequence? = mHintField.get(this) as CharSequence?
override fun getHint(): CharSequence? {
if (!buggyMeizu) {
return super.getHint()
} else {
val layout=getTIL()
return if (layout != null && (getTILProvidesHint()) )
layout.hint
else
provideHintWrapped()
}
}
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
val needHint=(outAttrs.hintText==null)
val ic = super.onCreateInputConnection(outAttrs)
if (buggyMeizu) {
if (ic != null && needHint) {
outAttrs.hintText = this.provideHintWrapped()
}
}
return ic
}
private fun provideHintWrapped():CharSequence? {
val hintFromLayout=getHintFromLayoutMine()
if (hintFromLayout!=null) {
return hintFromLayout
} else {
val baseHint=getBaseHint()
if (baseHint!=null) {
return baseHint
} else {
return null
}
}
}
private fun getHintFromLayoutMine(): CharSequence? {
val layout = getTIL()
return layout?.hint
}
override fun onAttachedToWindow() {
if (buggyMeizu) {
val baseHint=getBaseHint()
if (getTIL() != null
&& getTILProvidesHint()
&& baseHint == null) {
this.hint=""
}
}
super.onAttachedToWindow()
}
}
После этого находят и заменяют TextInputEditText с MyInputEditText во всем расположении и файлах кода.