Android TextView with Custom background? - android

I need a "Button" that would have a texture background, and dynamic text. The end result should be like this, but the background is a textured picture.
I tried to use a RelativeLayout with a TextView inside, but the problem is that the result CustomView does not wrap_content in width/height.
Here is the custom_buttonXML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#drawable/custom_button_selector"
android:layout_height="match_parent">
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_centerInParent="true"
/>
</RelativeLayout>
Here is the Code:
public class CustomButton extends RelativeLayout {
private LayoutInflater mInflater;
private RelativeLayout mContainer;
private TextView mTextView;
public CustomButton(Context context) {
super(context);
mInflater = LayoutInflater.from(context);
customInit(context);
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
mInflater = LayoutInflater.from(context);
customInit(context);
}
public CustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mInflater = LayoutInflater.from(context);
customInit(context);
}
private void customInit(Context ctx) {
mContainer = (RelativeLayout) mInflater.inflate(R.layout.cutom_button_view, this, true);
mTextView = (TextView) mContainer.findViewById(R.id.tv);
}
public RelativeLayout getContainer() {
return mContainer;
}
public TextView getTextView() {
return mTextView;
}
}
This is how I use it at the moment, and it works:
<com.myapp.views.CustomButton
android:id="#+id/btn"
android:layout_width="80dp"
android:layout_height="50dp"/>
But I want to use it like this (for dynamic text), and it won't work:
<com.myapp.views.CustomButton
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
It will actually stretch across the whole screen, ignoring the layout rules.
If this solution is a bad idea, could you recommend an alternative that would produce the same results?

You need to Shape file for that..
try out this.
<shape android:shape="rectangle">
<corners android:radius="56dp" />
<solid android:color="Color Whaterver You Want" />
<padding android:bottom="4dp" android:left="4dp" android:right="4dp" android:top="4dp" />
</shape>
Put this xml file under res/drawal folder.
now just in Your view pass this attribute..
android:background="#drawable/your file name"
Hop it works for you..

Custom layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/my_background">
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center" />
</RelativeLayout>
Custom layout java:
public class CustomButton extends FrameLayout {
private RelativeLayout mContainer;
private TextView mTextView;
public CustomButton(Context context) {
super(context);
customInit(context);
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
customInit(context);
}
public CustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
customInit(context);
}
private void customInit(Context ctx) {
LayoutInflater.from(ctx).inflate(R.layout.custom_button_viewa, this, true);
mContainer = (RelativeLayout) findViewById(R.id.container);
mTextView = (TextView) findViewById(R.id.tv);
}
public RelativeLayout getContainer() {
return mContainer;
}
public TextView getTextView() {
return mTextView;
}
}
Now can be used as:
<com.androidbolts.databindingsample.model.CustomButton
android:id="#+id/customButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

Related

Multiple layouts inside the single viewStub

I have an item which has apple, pear and lemon. I made separate layouts for apples, pears and lemons.
I want to get the layout of that element if any element is selected. I tried that put the correct layout to viewStub according to selected layout with inflate() function. But the performance of defining layouts with inflate() each time was exhausting and sometimes caused incorrect work.
Please help me.
My general view codes:
public class MyView extends RelativeLayout {
private ViewStub viewStub;
private int lemon = 1, apple = 2, pear = 3;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
this.viewStub = ViewUtil.findById(this, R.id.view_stub);
}
public void bindElements(int type){
if (type == lemon) {castLemon(); return;}
if (type == apple ) {castApple(); return;}
if (type == pear) {castPear(); return;}
public void castLemon() {
viewStub.setLayoutResource(R.layout.lemon_item);
LemonView lemonView = (LemonView) viewStub.inflate();
}
}
public void castApple() {
viewStub.setLayoutResource(R.layout.apple_item);
AppleView appleView = (AppleView) viewStub.inflate();
}
}
public void castPear() {
viewStub.setLayoutResource(R.layout.pear_item);
PearView pearView = (PearView) viewStub.inflate();
}
}
}
My general view xml:
<com.android.android.MyView
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:id="#+id/myView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout android:id="#+id/bodyLinear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ViewStub
android:id="#+id/view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:gravity="start|center_vertical"
android:paddingBottom="5dp"/>
</LinearLayout>
</com.android.android.MyView>
LemonView.java:
public class LemonView extends FrameLayout {
private ImageView imageView;
public LemonView(Context context) {
this(context, null);
}
public LemonView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LemonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.lemon_view, this);
imageView = findViewById(R.id.image);
}
lemon_view:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.android.android.LemonView">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:contentDescription="#null"
android:gravity="center"
android:scaleType="centerCrop"/>
</merge>
lemon_item xml:
<?xml version="1.0" encoding="utf-8"?>
<com.android.android.LemonView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lemon_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Create all the layouts at once, then just show / hide the needed layout variant with .setVisibility(View.VISIBLE) / .setVisibility(View.GONE).

cannot dynamically add views android

I'm trying to implement a custom view with textview children added dynamically. But it isn't showing any result. there are no error, just nothing shows up:
My Class:
public class CustomPasscodeEntryView extends LinearLayout {
private Context mContext;
private CustomPasscodeEntryView thisView;
public CustomPasscodeEntryView(Context context) {
super(context);
/* same as below */
}
public CustomPasscodeEntryView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
/*same as below*/
}
public CustomPasscodeEntryView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
thisView = (CustomPasscodeEntryView) inflater.inflate(R.layout.view_passcode_entry,this);
}
public void addDigit(int digit){
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final pinView pin = (pinView) inflater.inflate(R.layout.password_bullet_view,null);
pin.setDigit(digit);
thisView.addView(pin, thisView.getChildCount());
pin.setVisibility(VISIBLE);
}
public void deleteDigit(){
if(getChildCount() > 0)
thisView.removeView(thisView.getChildAt(getChildCount()-1));
}
}
class pinView extends TextView {
int digit;
public pinView(Context context) {
super(context);
}
public pinView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public pinView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setText('•');
}
public void setDigit(int digit) {
this.digit = digit;
this.setText(Integer.toString(digit));
}
}
and my XMLs:
view_passcode_entry:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:animateLayoutChanges="true">
</LinearLayout>
password_bullet_view:
<com.github.lockpin.lollipin.lib.views.pinView
xmlns:android="http://schemas.android.com/apk/res/android"
android:textColor="#android:color/white"
android:text="•"
android:textSize="20sp"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2.5dp"
/>
EDIT: the view in my activity:
<com.github.lockpin.lollipin.lib.views.CustomPasscodeEntryView
android:id="#+id/custom_passcode_entry_view"
android:layout_width="300dp"
android:layout_below="#id/pin_code_text_view"
android:layout_centerHorizontal="true"
android:layout_height="40dp"/>
I cant see what's wrong, and I've followed tutorials online and made a few changes. Am I missing something here? Or is this plainly wrong?
You use wrong view id view_passcode_entry when inflating view, which is instance of LinearLayout, and typecast it to CustomPasscodeEntryView.
You only need to use this when call addView() in addDigit() because CustomPasscodeEntryView is also instance of LinearLayout. So layout view_passcode_entry can be removed because it is not needed anymore.
this.addView(pin, this.getChildCount());
But if you want to add view view_passcode_entry as child of CustomPasscodeEntryView instance then you need to add thisView also
private ViewGroup thisView;
...
thisView = (ViewGroup) inflater.inflate(R.layout.view_passcode_entry, this);
this.addView(thisView, 0);
and then if you want to use view_passcode_entry as parent of pinView then you can use
thisView.addView(pin, thisView.getChildCount());
Is it because of you have already mentioned the height of CustomPasscodeEntryView in the xml (android:layout_height="40dp")?
Can you try wrap_content instead?

Why the error 'The following classes could not be instantiated in custom views' is showing in android?

In my app, I am creating views with extending relative class(For text view i am extending native textview in my java class) because I want to give custom font and don't want to apply font in every individual text view. For this I am using below code
public class LoyaltyTextView extends TextView {
private final static String DROID_SANS = "droid_sans";
public LoyaltyTextView(Context context) {
super(context);
}
public LoyaltyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(context, attrs);
}
public LoyaltyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
parseAttributes(context, attrs);
}
private void parseAttributes(Context context, AttributeSet attrs) {
TypedArray values = context.obtainStyledAttributes(attrs,R.styleable.LoyaltyTextView);
String typeface = values.getString(R.styleable.LoyaltyTextView_customTypeFace);
if(typeface.equalsIgnoreCase(DROID_SANS)) {
setTypeface(Typeface.createFromAsset(context.getAssets(), "DroidSans.ttf"));
}
values.recycle();
}
}
and i am using above custom control in xml as mentioned below
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:background="#drawable/bg_splash">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_above="#+id/tv_logo"
android:layout_centerHorizontal="true"
android:src="#drawable/logo_m" />
<customconstrols.LoyaltyTextView
android:id="#+id/tv_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:text="#string/loyalty_logo"
android:textSize="#dimen/logo_text_size"
android:textStyle="bold"
app:customTypeFace="DROID_SANS" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.customconstrols.LoyaltyTextView
android:layout_width="150dp"
android:layout_height="wrap_content"
android:text="#string/login"
/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
but when I use simple text views (as native android widget) it works fine but when i use above custom control preview section starts giving me error as mentioned in picture
I have tried number of solution which were mentioned in different post like clear cache/invalidate option and refresh layout and cleaning project and rebuilding it but nothing worked for me. Anything I am missing?
Replace your code as following line in your xml
xmlns:font="http://schemas.android.com/apk/res-auto"
Run your app,It will work fine.
public class MyFontTextView extends TextView {
private Typeface typeface;
public MyFontTextView(Context context) {
super(context);
}
public MyFontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public MyFontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.app);
String customFont = a.getString(R.styleable.app_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
private boolean setCustomFont(Context ctx, String asset) {
try {
if (typeface == null) {
typeface = Typeface.createFromAsset(ctx.getAssets(),
"fonts/OpenSans-Regular.ttf");
}
} catch (Exception e) {
AndyUtils.generateLog("Exception in component"+e);
return false;
}
setTypeface(typeface);
return true;
}
}
And in values -> attr.xml
<declare-styleable name="app">
<attr name="customFont" format="string" />
</declare-styleable>
Try this

How to initialize stuff that depends on the view’s attributes

Say I have this class MyView:
public class MyView extends GLSurfaceView {
private MyRenderer mRenderer;
public MyView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
init(ctx);
}
private void init(Context ctx) {
mRenderer = new MyRenderer(ctx);
setRenderer(mRenderer);
}
#Override
public void setBackground(Drawable background) {
mRenderer.setBackground(background);
}
}
That is inflated by MyActivity like this:
public class MyActivity extends Activity {
private MyView mView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
protected void init() {
setContentView(R.layout.my_layout);
mView = (MyView) findViewById(R.id.my_view);
}
}
To my knowledge setBackground is called by the inflater in setContentView, before init is called in MyView, so mRenderer has not been initialized yet.
It seems like a catch 22, because the view's attributes can't be set without the view's initialization, which happens after the attributes are set.
This is the layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#drawable/background" >
<com.developer.app.MyView
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/background"
/>
<TextView
android:id="#+id/left_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="#drawable/left_arrow"
/>
<TextView
android:id="#+id/right_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="#drawable/right_arrow"
/>
<TextView
android:id="#+id/home_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:background="#drawable/home"
/>
</RelativeLayout>
You are right. setBackground() is called from View's constructor if android:background attribute was parsed. In your case it called here:
super(ctx, attrs);
If you want to set background to mRenderer, you can do it in init:
private void init(Context ctx) {
mRenderer = new MyRenderer(ctx);
setRenderer(mRenderer);
final Drawable background = getBackground();
if (background != null) {
mRenderer.setBackground(background);
}
}
and add a null-check in setBackground, because this method can be called from superclass' constructor before you set some value to mRenderer
#Override
public void setBackground(Drawable background) {
if (mRenderer != null) {
mRenderer.setBackground(background);
}
}
What i understood from your question. You need attributes of views in oncreate(). But unable to do so. the reason is at that point UI is not initialized yet. there is work around.
this link might help.
getWidth() and getHeight() of View returns 0
You have initialize its three functions for example and xml and java is as you are doing it.
public class MyEditText extends EditText {
public MyEditText(Context context) {
super(context);
this.setTextColor(Color.parseColor("#4789da"));
this.setBackgroundResource(R.drawable.edittext_back);
this.setTextSize(18);
this.setPadding(5,5,5,5);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
this.setTextColor(Color.parseColor("#4789da"));
this.setBackgroundResource(R.drawable.edittext_back);
this.setTextSize(18);
this.setPadding(5,5,5,5);
}
public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setTextColor(Color.parseColor("#4789da"));
this.setBackgroundResource(R.drawable.edittext_back);
this.setTextSize(18);
this.setPadding(5,5,5,5);
}
}

Custom view not inflating layout when added programmatically

I'm trying to add a custom view to a linear layout programmatically. I want the custom view to inflate a layout I've already created. When I create an instance of the custom view and add it, a spot shows up where the view is, but the layout didn't seem to be inflated (set the background color of my custom layout to green, but I don't see green in the space, nor the image in the layout).
My custom view:
public class AddressView extends View {
public AddressView(Context context) {
super(context);
View.inflate(context, R.layout.place_address, null);
}
public AddressView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
View.inflate(context, R.layout.place_address, null);
}
public AddressView(Context context, AttributeSet attrs) {
super(context, attrs);
View.inflate(context, R.layout.place_address, null);
}
}
My custom view layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/address_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00ff00" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/house_1" />
</RelativeLayout>
My instantiation in an activity:
LinearLayout content = (LinearLayout) findViewById(R.id.content);
AddressView addressView = new AddressView(this);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, 400);
content.addView(addressView, 0, lp);
My R.id.content (The linear layout is the only child of a scrollview):
<LinearLayout
android:id="#+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/thumbnail_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="#drawable/test_house" />
</FrameLayout>
</LinearLayout>
I eventually worked around this by extending FrameLayout instead of View, and passing this to the inflate call. I think the view was being added and inflating, but it didn't know how to lay out the children correctly, which is resolved if you pass the parent to the inflate call initially:
public class AddressView extends FrameLayout {
public AddressView(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.place_address, this);
}
public AddressView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.place_address, this);
}
public AddressView(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.place_address, this);
}
}

Categories

Resources