I made a custom view that extends the View class:
import android.content.Context;
import android.graphics.Canvas;
import android.view.View;
public class DrawSurfaceView extends View
{
private ButtonsManager BM;
public DrawSurfaceView(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
BM.draw(canvas);
}
}
I included it in the xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextureView
android:id="#+id/gameSurface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.example.trashedometer.DrawSurfaceView
android:id="#+id/drawingSurface"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
But in the main code when it sets the content view it says it can't inflate my custom view, why?
setContentView(R.layout.activity_main);
You need at least one more constructor to allow inflation from an XML layout.
public class DrawSurfaceView extends View {
private ButtonsManager BM;
public DrawSurfaceView(Context context) {
this(context, null);
}
public DrawSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
...
}
Related
I made a custom layout that I want to implement for a RadioButton.
The code for the android class is here :
public class MyRadioButton extends LinearLayout implements View.OnClickListener{
private ImageView iv;
private TextView tv;
private RadioButton rb;
private View view;
public MyRadioButton(Context context) {
super(context);
view = View.inflate(context, R.layout.my_radio_button, this);
setOrientation(HORIZONTAL);
rb = (RadioButton) view.findViewById(R.id.radioButton1);
tv = (TextView) view.findViewById(R.id.textView1);
iv = (ImageView) view.findViewById(R.id.imageView1);
view.setOnClickListener(this);
rb.setOnCheckedChangeListener(null);
}
public void setImageBitmap(Bitmap bitmap) {
iv.setImageBitmap(bitmap);
}
public View getView() {
return view;
}
#Override
public void onClick(View v) {
boolean nextState = !rb.isChecked();
LinearLayout lGroup = (LinearLayout)view.getParent();
if(lGroup != null){
int child = lGroup.getChildCount();
for(int i=0; i<child; i++){
//uncheck all
((RadioButton)lGroup.getChildAt(i).findViewById(R.id.radioButton1)).setChecked(false);
}
}
rb.setChecked(nextState);
}
public void setImage(Bitmap b){
iv.setImageBitmap(b);
}
public void setText(String text){
tv.setText(text);
}
public void setChecked(boolean isChecked){
rb.setChecked(isChecked);
}
}
And the code for layout is here
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal" >
<RadioButton
android:id="#+id/radioButton1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="top"
android:text="" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/wow_visa_prepaid" />
</LinearLayout>
</LinearLayout>
At this moment, I can't figure out how to change the inheritance from LinearLayout to RadioButton and to keep the same layout.
This should like but with rounded corners
There are two ways to do the job:
1. When we hear about a custom view, it drives us to override onDraw method then drawing what we want into the view's Canvas.
2. In this case, there is a simpler approach, using drawableLeft. Here I've extended AppCompatRadioButton and set the considered layout as the drawableLeft.
MyRadioButton.java
package com.aminography.radiobutton;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import jp.wasabeef.glide.transformations.MaskTransformation;
// TODO: If you are using androidx
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatRadioButton;
// TODO: If you are using appcompat
//import android.support.annotation.Nullable;
//import android.support.v7.widget.AppCompatRadioButton;
public class MyRadioButton extends AppCompatRadioButton {
private View view;
private TextView textView;
private ImageView imageView;
public MyRadioButton(Context context) {
super(context);
init(context);
}
public MyRadioButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private RequestListener<Bitmap> requestListener = new RequestListener<Bitmap>() {
#Override
public boolean onLoadFailed(#Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
imageView.setImageBitmap(resource);
redrawLayout();
return false;
}
};
public void setImageResource(int resId) {
Glide.with(getContext())
.asBitmap()
.load(resId)
.apply(RequestOptions.bitmapTransform(
new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(dp2px(getContext(), 24), 0, RoundedCornersTransformation.CornerType.ALL))
)
)
.listener(requestListener)
.submit();
}
public void setImageBitmap(Bitmap bitmap) {
Glide.with(getContext())
.asBitmap()
.load(bitmap)
.apply(RequestOptions.bitmapTransform(
new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(dp2px(getContext(), 24), 0, RoundedCornersTransformation.CornerType.ALL))
)
)
.listener(requestListener)
.submit();
}
// setText is a final method in ancestor, so we must take another name.
public void setTextWith(int resId) {
textView.setText(resId);
redrawLayout();
}
public void setTextWith(CharSequence text) {
textView.setText(text);
redrawLayout();
}
private void init(Context context) {
view = LayoutInflater.from(context).inflate(R.layout.my_radio_button_content, null);
textView = view.findViewById(R.id.textView);
imageView = view.findViewById(R.id.imageView);
redrawLayout();
}
private void redrawLayout() {
view.setDrawingCacheEnabled(true);
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.buildDrawingCache(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
setCompoundDrawablesWithIntrinsicBounds(new BitmapDrawable(getResources(), bitmap), null, null, null);
view.setDrawingCacheEnabled(false);
}
private int dp2px(Context context, int dp) {
return (int) (dp * context.getResources().getDisplayMetrics().density);
}
}
my_radio_button_content.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ImageView
android:id="#+id/imageView"
android:layout_width="96dp"
android:layout_height="64dp"
android:src="#drawable/img_visa" />
</LinearLayout>
Visual Result:
Note:
1. If you're using appcompat in the project, do comment the androidx import at the top of class and uncomment appcompat one.
2. You can change the position of the custom layout simply by changing android:paddingLeft for your RadioButton:
<com.aminography.radiobutton.MyRadioButton
android:id="#+id/radioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="8dp" />
Edited:
I've rewritten the code to address the requirement of rounded corners image using Glide and Glide-Transformations.
build.gradle
dependencies {
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'jp.wasabeef:glide-transformations:3.3.0'
}
I have tried the following code and it works fine with no error:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="horizontal"
tools:context=".MainActivity">
<com.example.myapplication.MyRadioButton
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
After changing the following code from:
public MyRadioButton(Context context) {
to the following code:
public MyRadioButton(Context context, AttributeSet attributes) {
Is this the solution you need?
1. When you are creating class, that extends LinearLayout or
FrameLayout, .xml layout file (my_radio_button_content.xml),
must start with "merge" instead "LinearLayout", otherwise it
will be LinearLayot(.xml) in LinearLayout(your class).
<merge>
<RadioButton
android:id="#+id/radioButton1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="top"
android:text="" />
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/wow_visa_prepaid" />
</LinearLayout>
</merge>
2. It's easy to create: final ArrayList<MyRadioButton>, and pass it
to all children, if you want that brothers will change each
others.
public MyRadioButton(Context context) {
super(context);
inflate(context, R.layout.my_radio_button, this);
}
public void SetMyViewClickable(final ArrayList<String> brothers) {
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for (View brother:brothers) {
((RadioButton)brother.findViewById(R.id.radioButton1)).setChecked(false);
}
}
});
}
There are many ways to do this, for example, you can use the following libraries
https://github.com/AagitoEx/ImageRadioButton
https://github.com/ceryle/RadioRealButton
I use Spinner in my app, with keyboard opened.
This Spinner has 9 items (from 1 to 9).
However if keyboard is opened, spinner cannot be scrolled!
Thanks to it, some of items are out of screen, and I cannot select them.
Dialog Layout here:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.material.widget.FloatingEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/fet_productName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="#dimen/floating_edittext_margin"
android:layout_marginRight="#dimen/floating_edittext_margin"
android:hint="#string/product_name"
android:inputType="text" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/fet_productName"
android:layout_alignLeft="#+id/fet_productName"
android:layout_alignStart="#+id/fet_productName"
android:layout_alignRight="#+id/fet_productName"
android:layout_alignEnd="#+id/fet_productName"
android:layout_marginTop="#dimen/space_20dp"
android:id="#+id/linearLayout2">
<com.material.widget.FloatingEditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/fet_productUnit"
android:layout_weight="1"
android:hint="#string/product_unit"
android:inputType="text"
android:layout_marginRight="#dimen/space_6dp" />
<Spinner
android:layout_width="80dp"
android:layout_height="wrap_content"
android:id="#+id/sP_dialog_productNumber"
android:entries="#array/spinner_cart_item_number"
android:layout_marginLeft="#dimen/space_6dp" />
</LinearLayout>
</RelativeLayout>
Java code here:
public class CartFragment extends Fragment {
private Spinner spNum;
private MaterialDialog dialog;
private static String[] msITEMS;
private ArrayList<CartItemData> itemDatas;
private ArrayAdapter<String> strAdapter;
public CartFragment(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_placeholder_cart, container, false);
msITEMS = rootView.getContext().getResources().getStringArray(R.array.spinner_dialog_item_number);
strAdapter = new ArrayAdapter<String>(rootView.getContext(), R.layout.support_simple_spinner_dropdown_item, msITEMS);
strAdapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
final FloatingActionButton fabAdd = (FloatingActionButton)rootView.findViewById(R.id.fabAdd);
fabAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog = new MaterialDialog.Builder(getActivity())
.title(R.string.product_title)
.customView(R.layout.dialog_add_cartitem, false)
.positiveText(R.string.dialog_positive_add_cartitem)
.negativeText(R.string.dialog_negative_add_cartitem)
.show();
View view = dialog.getCustomView();
dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
spNum = (Spinner)view.findViewById(R.id.sP_dialog_productNumber);
fetName = (FloatingEditText)view.findViewById(R.id.fet_productName);
fetUnit = (FloatingEditText)view.findViewById(R.id.fet_productUnit);
spNum.setAdapter(strAdapter);
dialog.getActionButton(DialogAction.POSITIVE).setOnClickListener(onPositiveClick());
}
});
return rootView;
}
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
}
Create a custom scroll:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.holoeverywhere.widget.ListPopupWindow;
import org.holoeverywhere.widget.ListView;
import org.holoeverywhere.widget.Spinner;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
public class CustomSpinner extends Spinner
{
public CustomSpinner(Context context)
{
super(context);
}
public CustomSpinner(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public CustomSpinner(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
public CustomSpinner(Context context, AttributeSet attrs, int defStyle, int mode)
{
super(context, attrs, defStyle, mode);
}
public CustomSpinner(Context context, int mode)
{
super(context, mode);
}
#Override
public boolean performClick()
{
boolean bClicked = super.performClick();
try
{
Field mPopupField = Spinner.class.getDeclaredField("mPopup");
mPopupField.setAccessible(true);
ListPopupWindow pop = (ListPopupWindow) mPopupField.get(this);
ListView listview = pop.getListView();
Field mScrollCacheField = View.class.getDeclaredField("mScrollCache");
mScrollCacheField.setAccessible(true);
Object mScrollCache = mScrollCacheField.get(listview);
Field scrollBarField = mScrollCache.getClass().getDeclaredField("scrollBar");
scrollBarField.setAccessible(true);
Object scrollBar = scrollBarField.get(mScrollCache);
Method method = scrollBar.getClass().getDeclaredMethod("setVerticalThumbDrawable", Drawable.class);
method.setAccessible(true);
method.invoke(scrollBar, getResources().getDrawable(R.drawable.scrollbar_style));
if(VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB)
{
Field mVerticalScrollbarPositionField = View.class.getDeclaredField("mVerticalScrollbarPosition");
mVerticalScrollbarPositionField.setAccessible(true);
mVerticalScrollbarPositionField.set(listview, SCROLLBAR_POSITION_LEFT);
}
}
catch(Exception e)
{
e.printStackTrace();
}
return bClicked;
}
}
As shown on this other post by End.Fouad
I found one solution but it makes UX worse.
When the activity is appeared I focus a view which isn't a input view.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true" >
<com.material.widget.FloatingEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/fet_productName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="#dimen/floating_edittext_margin"
android:layout_marginRight="#dimen/floating_edittext_margin"
android:hint="#string/product_name"
android:inputType="text" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/fet_productName"
android:layout_alignLeft="#+id/fet_productName"
android:layout_alignStart="#+id/fet_productName"
android:layout_alignRight="#+id/fet_productName"
android:layout_alignEnd="#+id/fet_productName"
android:layout_marginTop="#dimen/space_20dp"
android:id="#+id/linearLayout2">
<com.material.widget.FloatingEditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/fet_productUnit"
android:layout_weight="1"
android:hint="#string/product_unit"
android:inputType="text"
android:layout_marginRight="#dimen/space_6dp" />
<Spinner
android:layout_width="80dp"
android:layout_height="wrap_content"
android:id="#+id/sP_dialog_productNumber"
android:entries="#array/spinner_cart_item_number"
android:layout_marginLeft="#dimen/space_6dp" >
</Spinner>
</LinearLayout>
<requestFocus/>
</RelativeLayout>
android:focusable="true"
android:focusableInTouchMode="true"
<requestFocus/>
Delete the following line in your 'Activity':
getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
or if you are using any such flags...
I want to have two custom views like this:
class LoadingView extends RelativeLayout{
//this view has a progressBar and can show and hide it.
void setIsLoading(){
// shows/hides progress bar
}
// some code ...
}
class OtherView extends LoadingView{
//some code ...
}
LoadingView has a layout like this:
<RelativeLayout>
<FrameLayout
id="#+id/content">
<!--this is where content goes-->
</FrameLayout>
<ProgressBar
id="#+id/pb"/>
</RelativeLayout>
so that any custom view that inherits from it will be injected into FrameLayout
so if OtherView has it's own layout , it will be nested inside FrameLayout automatically and you will be able to call myOtherView.setIsLoading(true/false)
How would you suggest doing this ?
Keep a reference to the content FrameLayout when inflating the first view.
public class LoadingView extends RelativeLayout {
private ProgressBar progressBar;
private FrameLayout contentFrame;
public LoadingView(Context context) {
super(context);
initialize();
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
private void initialize() {
View root = inflate(getContext(), R.layout.loading_view, this);
progressBar = (ProgressBar) root.findViewById(R.id.progress_bar);
contentFrame = (FrameLayout) root.findViewById(R.id.content_frame);
}
public void setLoading(boolean loading) {
progressBar.setVisibility(loading ? VISIBLE : GONE);
}
protected FrameLayout getContentFrame() {
return contentFrame;
}
}
Then use getContentFrame as the parent view when inflating the child view.
public class OtherView extends LoadingView {
public OtherView(Context context) {
super(context);
initialize();
}
public OtherView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public OtherView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize();
}
private void initialize() {
View root = inflate(getContext(), R.layout.other_view, getContentFrame());
}
}
loading_view.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
other_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">
<TextView
android:text="Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:text="Subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
And use it like this
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<com.example.client.ui.OtherView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
Why is the onClickListener not getting called in my extended LinearLayout? When i include Setting_1 in my activity's layout, the onClick does not trigger.
Here is the layout of the compound control :
setting.xml
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp" />
<TextView
android:id="#+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp" />
</LinearLayout>
Here is the abstract class that uses the above layout :
IntegerSettingLayout.java
public abstract class IntegerSettingLayout extends LinearLayout implements
OnClickListener {
public IntegerSettingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.setting, this, true);
}
...
#Override
//this is not getting called
public void onClick(View view) {
if(BuildConfig.DEBUG) {Log.d(LOG_TAG,"onClick");}
}
abstract String getStatus();
...
}
Here is the class that implements the above abstract class
Setting_1.java
public class setting_1 extends IntegerSettingLayout{
public Setting_WeekFrequency(Context context, AttributeSet attrs) {
super(context, attrs);
...
}
#Override
String getStatus() {
if(BuildConfig.DEBUG) {Log.d(LOG_TAG,"getStatus");}
}
}
You haven't actually registered your OnClickListener. You need to call setOnClickListener() for that, or use android:onClick attribute in XML.
Add this.setClickable(true); to your constructor.
package com.binod.customviewtest;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.RelativeLayout;
public class CustomView extends RelativeLayout{
public CustomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
// LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutInflater mInflater = LayoutInflater.from(context);
mInflater.inflate(R.layout.custom_view , this, true);
}
}
Including as
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.binod.customviewtest.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
></com.binod.customviewtest.CustomView>
</RelativeLayout>
Custom View as
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
</RelativeLayout>
Just started adding a new custom view and got the error once If I clear this then can move forward
I am getting crash "Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class"
You need to have 2 more constructors. To know why
Do I need all three constructors for an Android custom view?
public class CustomView extends RelativeLayout{
LayoutInflater mInflater;
public CustomView(Context context) {
super(context);
mInflater = LayoutInflater.from(context);
init();
}
public CustomView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
mInflater = LayoutInflater.from(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
mInflater = LayoutInflater.from(context);
init();
}
public void init()
{
View v = mInflater.inflate(R.layout.custom_view, this, true);
TextView tv = (TextView) v.findViewById(R.id.textView1);
tv.setText(" Custom RelativeLayout");
}
}
I am posting an example. My packagename is different
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.example.testall.CustomView
android:id="#+id/timer1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>
custom_view.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="60dp"
android:text="My Custom View" />
</RelativeLayout>
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Snap
As pskink suggested there in a RelativeLayout in activity_main.xml with a child CustomView. Then CustomView extends RealtiveLayout and then again you inflate a customview with RelativeLayout and a child TextView. No need for all these. Just a CustomView. Have a TextView created programatically and then add textview to RelativeLayout
Edit:
activity_main.xml
<com.example.testall.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/timer1"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
CustomView
public class CustomView extends RelativeLayout{
TextView tv;
public CustomView(Context context) {
super(context);
tv = new TextView(context);
init();
}
public CustomView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
tv = new TextView(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
tv = new TextView(context);
init();
}
public void init()
{
this.addView(tv);
tv.setText(" Custom RelativeLayout");
}
}
Try to get Activity and use this
{
LayoutInflater inflter = activity.getLayoutInflater();
View v = inflter.inflate(R.layout.custom_view,null);
this.addView(v); or addView(v);
}