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);
}
Related
I want to give attachment functionality in app . please see the attach screenshot.
How to create pro grammatically in Android ?
As I can see the solution of your problem. At first create the XML layout of your view. Then create class which will inflating in to it with GET methods. And then create this Views via code and add to container.
layout_custom.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="#+id/root"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="150dp">
<ImageView
android:id="#+id/img_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="12dp"
android:background="#000"/>
<ImageButton
android:id="#+id/btn_close"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="end"
android:background="#00000000"
android:scaleType="fitXY"
android:src="#drawable/temp_close"/>
</FrameLayout>
CustomView.class:
public class CustomView extends FrameLayout {
private View mRoot;
private ImageView mImgPhoto;
private View mBtnClose;
private Context mContext;
public CustomView(final Context context) {
this(context, null);
}
public CustomView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(final Context context) {
if (isInEditMode())
return;
final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View customView = null;
if (inflater != null)
customView = inflater.inflate(R.layout.layout_custom, this);
if (customView == null)
return;
mRoot = customView.findViewById(R.id.root);
mImgPhoto = (ImageView) customView.findViewById(R.id.img_photo);
mBtnClose = customView.findViewById(R.id.btn_close);
}
public View getRoot() {
return mRoot;
}
public ImageView getImgPhoto() {
return mImgPhoto;
}
public View getBtnClose() {
return mBtnClose;
}
}
And finnaly usage of this staff:
final CustomView customView1 = new CustomView(getBaseContext());
final CustomView customView2 = new CustomView(getBaseContext());
final LinearLayout container = (LinearLayout) findViewById(R.id.container);
container.addView(customView1);
container.addView(customView2);
You should create a frameLayout with 2 imageViews one that contains the actual image and one that contains the cross.
Create your custom_view.xml containing your frame layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
....>
<ImageView/>
<ImageView/>
</FrameLayout>
and then create a custom view class like this :
public class MyCustomView extends ViewGroup {
public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = LayoutInflater.from(context);
layoutInflater.inflate(R.layout.custom_view, this);
}
}
I'm trying to make something like the following screenshot (it's from an assignment from school):
As mentioned in the assignment, I have an Activity PlayActivity:
public class PlayActivity extends ActionBarActivity {
#Bind(R.id.activity_play_textView_score)
TextView txtScore;
#Bind(R.id.activity_play_board)
Board board;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
ButterKnife.bind(this);
}
}
The xml-layout for this activity:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/activity_play_textView_score"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/activity_play_textView_score_placeholder"/>
<com.charlotteerpels.game2048.Board
android:id="#+id/activity_play_board"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
We also had to make a class Card, which is an extension of a FrameLayout:
public class Card extends FrameLayout {
#Bind(R.id.card_frame_layout_textView)
TextView txtNumber;
private int number;
public void setTxtNumber(TextView txtNumber) {
this.txtNumber = txtNumber;
}
public TextView getTxtNumber() {
return this.txtNumber;
}
public void setNumber(int number) {
this.number = number;
}
public int getNumber() {
return this.number;
}
public Card(Context context, AttributeSet attributeSet, int defaultStyle) {
super(context, attributeSet, defaultStyle);
inflateLayout();
ButterKnife.bind(this);
}
public Card(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
inflateLayout();
ButterKnife.bind(this);
}
public Card(Context context) {
super(context);
inflateLayout();
ButterKnife.bind(this);
}
private void inflateLayout() {
String infService = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater li = (LayoutInflater)getContext().getSystemService(infService);
li.inflate(R.layout.card_frame_layout, this, true);
}
}
The xml-layout for this class:
<?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"
android:background="#color/card_frame_layout_background"
android:layout_margin="4dp">
<TextView
android:id="#+id/card_frame_layout_textView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/card_frame_layout_textView_placeholder"
android:textSize="40sp"
android:layout_gravity="center"/>
</FrameLayout>
At least we had to make a class Board, which is an extension of a GridLayout:
public class Board extends GridLayout {
Card[][] cardBoard;
public Board(Context context, AttributeSet attributeSet, int defaultStyle) {
super(context, attributeSet, defaultStyle);
initBoard(context);
}
public Board(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
initBoard(context);
}
public Board(Context context) {
super(context);
initBoard(context);
}
public void initBoard(Context context) {
//Set the settings for the GridLayout (the grid is the board)
String infService = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater li = (LayoutInflater)getContext().getSystemService(infService);
li.inflate(R.layout.board_grid_layout, this, true);
//Initialize the cardBoard[][] and populate it
cardBoard = new Card[4][4];
for(int rij=0; rij<4; rij++) {
for(int kolom=0; kolom<4; kolom++) {
cardBoard[rij][kolom] = new Card(getContext());
}
}
int cardMeasure = getCardMeasure(context);
addCardBoardToGridLayout(cardMeasure);
}
private void addCardBoardToGridLayout(int cardMeasure) {
for(int rij=0; rij<4; rij++) {
for(int kolom=0; kolom<4; kolom++) {
Card card = cardBoard[rij][kolom];
addView(card, cardMeasure, cardMeasure);
}
}
}
private int getCardMeasure(Context context) {
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenWidth = size.x;
return screenWidth/4;
}
}
The xml-layout for the Board:
<?xml version="1.0" encoding="utf-8"?>
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/board_grid_layout_background"
android:columnCount="4"
android:rowCount="4">
</GridLayout>
But all I'm getting is this:
I'm also using Butterknife (website: http://jakewharton.github.io/butterknife/)
for binding resources, but mostly to bind views and elements from the xml-layouts.
Can anybody help me?
Found what was wrong!
So in the xml-layout from Card, I changed the layout_width and layout_height from the TextView:
<?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"
android:background="#color/card_frame_layout_background"
android:layout_margin="4dp">
<TextView
android:id="#+id/card_frame_layout_textView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/card_frame_layout_textView_placeholder"
android:textSize="40sp"
android:layout_gravity="center"/>
</FrameLayout>
The "addCardBoardToGridLayout(int cardMeasure)" changed to the following:
private void addCardBoardToGridLayout(int cardMeasure) {
setRowCount(4);
setColumnCount(4);
removeAllViews();
for(int rij=0; rij<4; rij++) {
for(int kolom=0; kolom<4; kolom++) {
Card card = cardBoard[rij][kolom];
addView(card, cardMeasure, cardMeasure);
}
}
}
Now it looks like this (and it's exactly like I wanted it!):
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>
I'm trying to add CustomViewBeta (an extended RelativeLayout) to CustomViewAlpha (an extended LinearLayout) -- the idea being that the CustomViewAlpha will hold a bunch of CustomViewBetas a la a ListView. No matter what I try, it doesn't work. I either see nothing -- no CustomViewBetas, or it gives me an NPE when I try setText on one of the TextViews inside the CustomViewBeta
CustomViewAlpha works fine since it's hard-coded in the Fragment's XML:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
...>
<com.path.CustomViewAlpha
android:id="#+id/customviewalpha"
android:orientation="vertical"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
With the code being:
public class CustomViewAlpha extends LinearLayout {
private Context mContext;
public CustomViewAlpha (Context context) {
super(context);
this.mContext = context;
}
public CustomViewAlpha (Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
}
public CustomViewAlpha (Context context, AttributeSet attrs, int defStyle){
super(context, attrs,defStyle);
this.mContext = context;
}
public void addCustomViewBeta(String someString){
CustomViewBeta customViewBeta = new CustomViewBeta(mContext);
addView(customViewBeta);
}
CustomViewBeta is not hard-coded in the Fragment's XML and get's added programmatically:
public class CustomViewBeta extends RelativeLayout{
private Context mContext;
private TextView textView;
public CustomViewBeta (Context context) {
super(context);
this.mContext = context;
init();
}
public CustomViewBeta (Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}
public CustomViewBeta (Context context, AttributeSet attrs, int defStyle){
super(context, attrs,defStyle);
this.mContext = context;
init();
}
private void init() {
LayoutInflater.from(mContext).inflate(R.layout.customviewbeta, null, false);
textView = (TextView) findViewById(R.id.tripleexpandablelistview_category_name);
textView.setText("ASDASDASDAD");
}
With this XML being:
<?xml version="1.0" encoding="utf-8"?>
<com.path.CustomViewBeta
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/customviewbeta_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</com.path.CustomViewBeta>
I usually get hit with a NPE on the "textView.setText("ASDASDASDAD");" line because the TextView is null. Is there something I'm missing? Should I not try to inflate an XML for the CustomViewBeta and just do it programmatically (adding the textviews one by one programmatically?)? Thanks.
your init is wrong
private void init() {
LayoutInflater.from(mContext).inflate(R.layout.customviewbeta, null, false);
textView = (TextView) findViewById(R.id.tripleexpandablelistview_category_name);
textView.setText("ASDASDASDAD");
}
the last parameter has to be true to add the TextViewto the RelativeLayout.Also ViewGroup, has a static inflate method, so you can avoid LayoutInflater.from(mContext), you can just call inflate(mContext, R.layout.customviewbeta, this);
I have extended a RelativeLayout with all its constructor.And I have created a layout in xml that I am inflating in one of constructor of my class.
My Code for MyClass
public class MyClass extends RelativeLayout
{
LayoutInflater inflater = null;
EditText edit_text;
Button btn_clear;
public MyClass(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MyClass(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_class_layout, this, true);
edit_text = (EditText) findViewById(R.id.clearable_edit);
btn_clear = (Button) findViewById(R.id.clearable_button_clear);
btn_clear.setVisibility(RelativeLayout.INVISIBLE);
}
public MyClass(Context context)
{
super(context);
// TODO Auto-generated constructor stub
}
}
My class layout which I inflate
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="#+id/clearable_edit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="#+id/clearable_button_clear"
android:layout_width="30dip"
android:layout_height="30dip"
android:layout_alignParentRight="true"
android:background="#drawable/image_clear"
android:layout_centerVertical="true"
android:layout_marginRight="5dip"/>
</RelativeLayout>
And I use MyClass in my activity's layout like this
<com.and.MyClass
android:id="#+id/my_class"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
This works fine.
but when I inflate my class layout in constructor MyClass(Context context) then it doesn't work.
I am not getting what is the problem. I hope you got my question.
This is OK.
When we use a View in xml
public MyClass(Context context, AttributeSet attrs)
this constructor will be called.
Because all the attributes from XML are passed to this constructor using AttributeSet, so that these values will have effect on View's layout and other fields.
However if you want to use your View in Java also, you should also inflate in all View's constructor (Which is recommended approach).
Please change your code like this
public class MyClass extends RelativeLayout
{
LayoutInflater inflater = null;
EditText edit_text;
Button btn_clear;
public MyClass(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
public MyClass(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public MyClass(Context context)
{
super(context);
// TODO Auto-generated constructor stub
init();
}
public void init() {
inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_class_layout, this, true);
edit_text = (EditText) findViewById(R.id.clearable_edit);
btn_clear = (Button) findViewById(R.id.clearable_button_clear);
btn_clear.setVisibility(RelativeLayout.INVISIBLE);
}
}