As the title says, I have implemented this simple custom textView. The idea would be to apply a style that I choose by passing it through xml.
The class I created, however, is never called, in fact in debug it never stops at the breakpoints I entered.
In particular, the class I am using is the following
class MyTextView : AppCompatTextView {
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
context, attrs, defStyle
) {
init(attrs)
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(attrs)
}
constructor(context: Context) : super(context) {
init(null)
}
private fun init(attrs: AttributeSet?) {
if (attrs != null) {
val a = context.obtainStyledAttributes(attrs, R.styleable.MyTextView)
val fontName = a.getString(R.styleable.MyTextView_fontName)
if (fontName != null) {
val myTypeface = Typeface.createFromAsset(context.assets, "fonts/$fontName")
typeface = myTypeface
}
a.recycle()
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
this.text = "new text"
}
}
Here my xml:
<com.example.utils.widget.MyTextView
android:id="#+id/myText"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:elevation="20dp"
android:text="MyText"
app:fontName="ultrabold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
and here the attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyTextView">
<attr name="fontName" format="string"/>
</declare-styleable>
</resources>
All compile correctly but I can't see my textview and not invoked by breakpoints. Anyone know why?
Related
I have recently updated Android Studio to Android Studio Electric Eel | 2022.1.1.
For xml layout if we are using simple view like TextView/Button , it is displayed on preview.
But if we are using CustomView, then it is not showing in preview.(Preview is blank)
Also it is showing error: Missing classes
My Simple Test App , main activity xml file is as
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.webviewdeeplink.CustomTextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is Test Text"
android:textSize="24sp"
app:font="RobotoCondensed-LightItalic.ttf"
app:layout_constraintBottom_toTopOf="#id/button"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Custom Component class -
class CustomTextView : androidx.appcompat.widget.AppCompatTextView {
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
context!!,
attrs,
defStyle
) {
init(attrs)
}
constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {
init(attrs)
}
constructor(context: Context?) : super(context!!) {
init(null)
}
private fun init(attrs: AttributeSet?) {
if (attrs != null) {
val a = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView)
val fontName = a.getString(R.styleable.CustomTextView_font)
try {
if (fontName != null) {
val myTypeface = Typeface.createFromAsset(
context.assets,
"fonts/$fontName"
)
setTypeface(myTypeface)
}
} catch (e: Exception) {
e.printStackTrace()
}
a.recycle()
}
}
}
If any one faced this issue , could you please confirm issue.
OR this is known Android Studio Issue?
try this code...
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
context!!,
attrs,
0
) {
init(attrs)
}
Replace defStyle with 0
Change the build variant to debug
Clean and Rebuild the project
This will fix the issue.
I am trying to create compound CardView using two CardView and extended Framelayout. If I place a button inside custom CardView as a child the button is visible but if i place TextView or ImageView as a child the widget (TextView or ImageView) is not visible.
Screenshot of Custom widget with TextView as child
Screenshot of Custom Widget with Button as child
kotlin code
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import androidx.cardview.widget.CardView
class CompoundCardView : FrameLayout{
private var childView:CardView? = null
private var heading:String? = null
set(value) {
field = value
invalidate()
requestLayout()
}
get() {
return field
}
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context,
attrs: AttributeSet,
defStyle: Int) : super(context, attrs, defStyle) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
context.theme.obtainStyledAttributes(attrs,R.styleable.CompoundCardView,0,0).apply {
try {
heading = getString(R.styleable.CompoundCardView_heading)
}finally {
recycle()
}
}
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
inflater.inflate(R.layout.compaund_card_view,this,true)
childView = findViewById(R.id.holder)
val header:TextView = findViewById(R.id.header)
header.text = heading
}
override fun addView(child: View?) {
invalidate()
childView?.addView(child,0, child?.layoutParams)
requestLayout()
}
}
xml layout
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.card.MaterialCardView
android:id="#+id/holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="20dp"
android:background="#00FFFFFF"
app:cardCornerRadius="8dp"
app:strokeColor="#2196F3"
app:strokeWidth="1dp" />
<com.google.android.material.card.MaterialCardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:backgroundTint="#FFC107"
app:cardCornerRadius="8dp"
app:contentPaddingBottom="4dp"
app:contentPaddingLeft="8dp"
app:contentPaddingRight="8dp"
app:contentPaddingTop="4dp"
app:strokeColor="#2196F3"
app:strokeWidth="1dp">
<TextView
android:id="#+id/header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="#string/heading"
android:textSize="20sp" />
</com.google.android.material.card.MaterialCardView>
</merge>
In my application I create one custom view for show TextView and FontAwesome!
I write below codes, but not set values and just show default values!
TextWithIcon class :
class TextWithIcon #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0,
defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyle, defStyleRes) {
init {
LayoutInflater.from(context).inflate(R.layout.layout_text_with_awesome, this, true)
orientation = VERTICAL
attrs?.let {
val typedArray = context.obtainStyledAttributes(R.styleable.TextWithIcon)
val title = resources.getText(
typedArray.getResourceId(
R.styleable.TextWithIcon_customText,
R.string.app_name
)
)
val icon = resources.getText(
typedArray.getResourceId(
R.styleable.TextWithIcon_customIcon,
R.string.app_name
)
)
val titleTxt = getChildAt(0) as TextView
titleTxt.text = title
Log.e("titleTxt",title.toString())
//binding.iconTxt.text = "&#x$icon"
typedArray.recycle()
}
}
}
CustomViewLayout file :
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="#+id/titleTxt"
android:layout_width="wrap_content"
android:layout_height="#dimen/_20mdp"
android:gravity="right"
android:textColor="#color/darkJungleGreen"
android:textSize="#dimen/_10font_mdp" />
<com.myapp.utils.views.FontAwesome
android:id="#+id/iconTxt"
android:layout_width="#dimen/_20mdp"
android:layout_height="#dimen/_20mdp"
android:layout_gravity="right"
android:gravity="center"
android:textColor="#color/beauBlue"
android:textSize="#dimen/_10font_mdp"
app:fontPath="fonts/fontawesome_re.ttf" />
</merge>
And I used this class with code in XML :
<com.myapp.TextWithIcon
android:id="#+id/item1Title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="#dimen/_10mdp"
android:drawablePadding="#dimen/_5mdp"
android:gravity="center"
android:textColor="#color/ochre"
android:textSize="#dimen/_10font_mdp"
app:customIcon="f007"
app:customText="wegwergewrg"
app:fontPath="fonts/iransans_bold.ttf"
app:layout_constraintEnd_toStartOf="#id/item1Line"
app:layout_constraintTop_toTopOf="#id/item1Line" />
I set value with this code : app:customText="wegwergewrg", but not show this and just show default value from
resources.getText(
typedArray.getResourceId(
R.styleable.TextWithIcon_customText,
R.string.app_name
)
)
How can I fix it?
You are going to want your styleable to look something like this:
<resources>
<declare-styleable name="TextWithIcon">
<attr name="customText" format="reference|string" />
</declare-styleable>
</resources>
This definition will permit you to use text as well as a string resource id for "app:customText".
You can get the value from the attribute as follows:
class TestCustomView #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : androidx.appcompat.widget.AppCompatTextView(context, attrs) {
init {
val a = context.obtainStyledAttributes(attrs, R.styleable.TextWithIcon)
for (attr in 0 until a.indexCount) {
when (a.getIndex(attr)) {
R.styleable.TextWithIcon_customText -> {
text = a.getText(attr) ?: "Unknown text."
}
}
}
a.recycle()
}
}
I'm using custom editText for showing number value, It working in most of the time but some time it throw IndexOutOfBoundsException.
CustomEditText,
class FixedCursorEditText : EditText {
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
override fun onSelectionChanged(selStart: Int, selEnd: Int) {
this.text?.length?.let { this.setSelection(it) }
}
}
XML file,
<sample.example.views.FixedCursorEditText
android:id="#+id/enterAmountEditText"
android:layout_width="0dp"
android:layout_height="64dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:backgroundTint="#color/colorPrimaryText"
android:digits="0123456789"
android:inputType="number"
android:text="#={ viewModel.amount }"
android:textColor="#color/colorPrimaryText"
android:textSize="32sp"
app:backgroundTint="#color/colorPrimaryText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
>
<requestFocus />
<sample.example.views.FixedCursorEditText>
In fragment,
var currentValue = viewModel.parse(viewModel.amount.value) ?: 0
currentValue += amount
viewModel.amount.value = currentValue.toString()
enterAmountEditText.text?.length?.let { enterAmountEditText.setSelection(it) }
Can you help me for solving this issue.
Error log,
IndexOutOfBoundsException: offset(3) should be less than line limit(0)
at sample.example.views.FixedCursorEditText.onSelectionChanged(FixedCursorEditText.kt:15)
at sample.example.databinding.FragmentAmountBindingImpl.executeBindings(FragmentAmountBindingImpl.java:291)
I want to have my CustomTextInputLayout to have Widget.MaterialComponents.TextInputLayout.OutlinedBox as default style without defining it anywhere in the XML.
I tried this
class CustomTextInputLayout #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TextInputLayout(ContextThemeWrapper(context, R.style.Widget_MaterialComponents_TextInputLayout_OutlinedBox), attrs, defStyleAttr) {
}
and this
class CustomTextInputLayout #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TextInputLayout(context, attrs, R.style.Widget_MaterialComponents_TextInputLayout_OutlinedBox)
but it's not working. I've tried the default XML way
<com.custom.CustomTextInputLayout
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
...>
<com.google.android.material.textfield.TextInputEditText
...
android:hint="Sample Hint" />
</com.custom.CustomTextInputLayout>
and it's working.
What am I missing here?
How can I set a default style for custom TextInputLayout without using XML?
It is not exactly what you are looking for.
You can define:
public class CustomTextInputLayout #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.textInputStyle
) : TextInputLayout(ContextThemeWrapper(context, R.style.Outlined_Theme), attrs, defStyleAttr) { ... }
with:
<style name="Outlined.Theme" parent="">
<item name="textInputStyle">#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox</item>
</style>
Then in your layout juse use:
<com.example.quicksample.CustomTextInputLayout
....
android:hint="Sample">
<com.google.android.material.textfield.TextInputEditText../>
</com.example.quicksample.CustomTextInputLayout>
Your code doesn't work because ContextThemeWrapper(context, R.style.Widget_MaterialComponents_TextInputLayout_OutlinedBox) the 2nd parameter has to be an attribute theme and not a style (it is the same for TextInputLayout(context, attrs, R.style.Widget_MaterialComponents_TextInputLayout_OutlinedBox))