Custom onClickListner in custom widget - how? - java

I have a custom widget thats extends Linear layout.
It just block of text with litle.
Here is xml of widget:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:background="#drawable/actionbar_background"
android:layout_height="35dp"
android:paddingLeft="15dp"
android:gravity="center_vertical">
<TextView
android:id="#+id/title"
android:layout_height="35dp"
android:textColor="#color/white"
android:layout_width="match_parent"
android:textSize="18dp"
android:clickable="true"
android:gravity="center_vertical" />
</LinearLayout>
<TextView
android:id="#+id/ingreds"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="Some text"
android:paddingLeft="15dp" />
</LinearLayout>
If I creating onClickListener for that custom widget somewhere in Activity - it reacts only if I click on last TextView in that layout. But I need to set onClickListener for horizontal LinearLayout which contains "title" textView, or directly on title TextView.
Important: I want to set these listeners OUTSIDE the custom widget class.
I think that I need to override setOnclickListener method in my custom class or something like that, but I'm not sure how it can be done.
Here is the class of custom widget:
public class MyTextBlock extends LinearLayout {
private TextView title;
private TextView ingreds;
public MyTextBlock(Context context) {
this(context, null);
}
public MyTextBlock(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_text_block, this, true);
title = (TextView) findViewById(R.id.title);
ingreds = (TextView) findViewById(R.id.ingreds);
}
public void setText(String text) {
ingreds.setText(text);
}
public void setTitle(String titleText) {
title.setText(titleText);
}
}
Thanks for answering.

Just implement the OnClickListener to this view class and set textview.setOnClickLister(this);
now handle the click event under the onClick(View v) method.

MyTextBlock textviewCustom = ....
textviewCustom.setonclickListner(MainClass.this);
public class MyTextBlock extends LinearLayout {
private TextView title;
private TextView ingreds;
public MyTextBlock(Context context) {
this(context, null);
}
public MyTextBlock(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.my_text_block, this, true);
title = (TextView) findViewById(R.id.title);
ingreds = (TextView) findViewById(R.id.ingreds);
}
public void setonclickListner(OnclickListner listner)
{
title.setonclicklistner(listner);
ingreds.setonclicklistner(listner);
}
public void setText(String text) {
ingreds.setText(text);
}
public void setTitle(String titleText) {
title.setText(titleText);
}
}

Related

Custom view returns NULL when initialized

I want to create a custom reusable view to show in a gridlayout.
I can't seem to get the view to initialize. It always returns null in my Activity
Can anyone help me understand what I am doing wrong? I feel like it is in my Tile constructor.
My Activity:
private void addTile() {
TileView tile = new TileView(this);
tile.setTextTitle("CALLS");
tile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tilePressed(v);
}
});
mGridLayout.addView(tile);
}
The GridLayout portion of the Activity's XML:
<GridLayout
android:id="#+id/glTileArea"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/COLOR_LIGHT_GREEN"
android:columnCount="2"
android:rowCount="2" >
</GridLayout>
My reusable view:
public class TileView extends View{
private View mView;
private Context mContext;
private TextView mTitle;
public TileView(Context context) {
super(context);
this.mContext = context;
}
public View TileView(){
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
mView = inflater.inflate(R.layout.sample_tile_view,null);
mTitle = (TextView) mView.findViewById(R.id.tvTitle);
return mView;
}
public void setTextTitle(String text){
mTitle.setText(text);
}
}
The XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/COLOR_BLUE"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="TITLE"
android:textAlignment="center"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#color/COLOR_WHITE"
android:textStyle="bold"/>
</LinearLayout>
Error that I get:
Attempt to invoke virtual method 'void
android.widget.TextView.setText(java.lang.CharSequence)' on a null
object reference at com.mycompany.myapp.Views.TileView.setTextTitle
(TileView.java:77)
Problem is due to:
tile.setTextTitle("CALLS");
line. mTitle is null because TileView() method is not called anywhere in which initializing TextView.
Either call TileView() before calling setTextTitle method:
tile.TileView();
tile.setTextTitle("CALLS");
or call TileView method in constructor :
public TileView(Context context) {
super(context);
this.mContext = context;
this.TileView(); //<< call here
}
Try to move the code in TileView() to TileView(Context context)
public TileView(Context context) {
super(context);
this.mContext = context;
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
mView = inflater.inflate(R.layout.sample_tile_view,null);
mTitle = (TextView) mView.findViewById(R.id.tvTitle);
}

Custom Font in ListView

So I am trying to set a custom font (hello.ttf) which is already in the assets folder to a ListView. Below is my java and xml file.
faListFragment.java
public class faListFragment extends Fragment {
public faListFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_fa_list, container, false);
String[] faList = { "One",
"Two",
};
ListView listView = (ListView) view.findViewById(R.id.listFa);
ArrayAdapter<String> listviewAdapter = new ArrayAdapter<String>(
getActivity(),
android.R.layout.simple_list_item_1,
faList
);
listView.setAdapter(listviewAdapter);
// Inflate the layout for this fragment
return view;
}
}
and this is my fragment_fa_list.xml
<FrameLayout 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="com.me.hello.faListFragment">
<!-- TODO: Update blank fragment layout -->
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/listFa" />
</FrameLayout>
I have tried several ways of adding the font, but cant quite seem to grasp how to go about it.
You have to create one layout xml in layout folder. In that layout xml you have to user custom textview with custom font.
For CustomTextView Link : Using custom font in android TextView using xml
ArrayAdapter<String> listviewAdapter = new ArrayAdapter<String>(
getActivity(),
R.layout.row_item, R.id.text ,
faList
);
listView.setAdapter(listviewAdapter);
Edit :
My CustomTextView Class
public class MyTextView extends TextView {
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyTextView(Context context) {
super(context);
init();
}
private void init() {
if (!isInEditMode()) {
Typeface tf = Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Regular.ttf");
setTypeface(tf);
}
}
}
row_item.xml
<RelativeLayout 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="wrap_content"
android:layout_margin="15dp"
android:background="#00000000"
android:orientation="vertical">
<pakagename.MyTextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/title"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:text="CEO"
android:textColor="#000"
android:textSize="16dp" />
</RelativeLayout>

Create custom layout in XML to initialize in code or in another layout xml

I have encountered an issue i am trying to resolve (or understand better the way it should be done) in creation of custom Layout in Android.
I want to create a custom RelativeLayout class for my use, which is defined in a layout XML file.
my_relative_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<com.mypackage.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:scaleType="fitStart"
android:src="#drawable/my_drawable"/>
<TextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/title_gray"
android:layout_below="#id/image_view"
android:gravity="center"
android:text="#string/placeholder" />
</com.mypackage.MyRelativeLayout>
Usage
public class MyRelativeLayout extends RelativeLayout {
private AttributeSet attrs;
private ImageView imageView;
private TextView textView;
public MyRelativeLayout(Context context) {
super(context);
}
public MyRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
this.attrs = attrs;
}
public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.attrs = attrs;
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
if (attrs != null) {
TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.MyRelativeLayout, 0, 0);
drawableResource = a.getResourceId(R.styleable.MyRelativeLayout.image_view, 0);
a.recycle();
}
imageView = (ImageView) findViewById(R.id.image_view);
textView = (TextView) findViewById(R.id.text_view);
if (drawableResource != 0 && imageView != null) {
imageView.setImageResource(drawableResource);
}
}
}
My issue is that i want to initialise this layout both in another XML and in code.
But as I wrote my class and XML, i can only use it in code by doing:
myLayout = (MyRelativeLayout) LayoutInflater.from(this.getActivity()).inflate(R.layout.my_relative_layout, container, false);
When writing the following in another XML causes the onFinishInflate to fail on getViewById (returns null) and the childrenCount is 0
<com.mypackage.MyRelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="#id/another_layout"
app:image_view="#drawable/my_image" />
and doing the following, won't let me configure the custom image_view attribute.
<include layout="#layout/my_relative_layout"/>
To fix that, i can change the custom layout XML root element to be of type RelativeLayout and add the following to the beginning of onFinishInflate method:
LayoutInflater.from(getContext()).inflate(R.layout.my_relative_layout, this, true);
But the XML won't reference my class.
My questions are,
1. Am i missing something in the definition of the custom layout?
2. What is the correct definition for custom layout?
Thank you in advance!
First you should use the styled attributes in the contractor as shown in this example.
How can you expect from MyRelativeLayout that defined as fallow:
<com.mypackage.MyRelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="#id/another_layout"
app:image_view="#drawable/my_image" />
To be aware of views that are defined in my_relative_layout.xml?
To make it work you should create a costume layout and add it to com.mypackage.MyRelativeLayout manually.
Some thing like that:
costume_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null"
android:scaleType="fitStart"
android:src="#drawable/my_drawable"/>
<TextView
android:id="#+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/title_gray"
android:layout_below="#id/image_view"
android:gravity="center"
android:text="#string/placeholder" />
</RelativeLayout>
Your costume view
public class MyRelativeLayout extends RelativeLayout {
private AttributeSet attrs;
private ImageView imageView;
private TextView textView;
public MyRelativeLayout(Context context) {
super(context);
init();
}
public MyRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(Context context){
LayoutInflater.from(context).inflate(R.layout.costume_layout, this);
}
}

findViewById(R.id.view_id) returns null in case of composite view

Compound view xml code:-
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/dayRelativeLayout"
android:layout_width="30dip"
android:layout_height="45dip"
android:background="#drawable/selectable_day_layout_border">
<TextView android:id="#+id/eventTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:textSize="12dip"
android:visibility="invisible"
android:layout_margin="2.1dip"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
android:id="#+id/dayTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:layout_below="#+id/eventTextView"
android:textAppearance="?android:attr/textAppearanceSmall"/>
</RelativeLayout>
Below is the java code for the above compound control:-
public class CalendarGridView extends RelativeLayout
{
private Context context = null;
private TextView eventTextView = null;
private TextView dayTextView = null;
public CalendarGridView(Context context)
{
super(context);
this.context = context;
init();
}
public CalendarGridView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.context = context;
init();
}
public CalendarGridView(Context context, AttributeSet attrs,int defStyle)
{
super(context, attrs, defStyle);
this.context = context;
init();
}
private void init()
{
int id = (int)Math.abs(Math.random()*100000);
super.setId(id);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
addView(inflater.inflate(R.layout.day_view, null));
eventTextView = (TextView) findViewById(R.id.eventTextView);
dayTextView = (TextView) findViewById(R.id.dayTextView);
eventTextView.setOnClickListener(new GridClickListener());
dayTextView.setOnClickListener(new GridClickListener());
}
public TextView getEventTextView()
{
return eventTextView;
}
public TextView getDayTextView()
{
return dayTextView;
}
class GridClickListener implements OnClickListener
{
#Override
public void onClick(View v)
{
calculateClickedGrid(v);
}
}
private void calculateClickedGrid(View v)
{
int id = ((ViewGroup)v.getParent()).getId();
GridCordinates cordinates = GridViewUtil.getGridCordinate(id);
if(cordinates != null)
{
}
}
}
Below is the gridlayout xml code in which i am using above compound control:-
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:rowCount="8"
android:columnCount="7"
android:background="#drawable/selectable_day_layout_border">
<!-- Row 0-->
<ImageButton
android:id="#+id/previousMonthImageButton"
android:layout_row="0"
android:layout_columnSpan="1"
android:layout_column="0"
android:layout_gravity="center"
android:layout_margin="3dip"
android:padding="3dip"
android:background="#7F7CD9"
android:src="#drawable/navigation_previous_item"/>
<TextView
android:id="#+id/monthNameTextView"
android:text="September"
android:layout_row="0"
android:layout_columnSpan="5"
android:layout_column="1"
android:layout_gravity="center"
android:layout_margin="3dip"
android:padding="3dip"
android:textSize="25dip"
android:background="#7F7CD9"/>
<ImageButton
android:id="#+id/nextMonthImageButton"
android:layout_row="0"
android:layout_columnSpan="1"
android:layout_column="6"
android:layout_gravity="center"
android:layout_margin="3dip"
android:padding="3dip"
android:background="#7F7CD9"
android:src="#drawable/navigation_next_item"/>
<!-- Row 1-->
<com.gp.app.minote.calendar.ui.CalendarGridView
android:id="#+id/day1"
android:layout_row="2"
android:layout_column="0"
android:layout_width="30dip"
android:layout_height="40dip"
android:layout_margin="2dip"
android:padding="3dip"
android:layout_gravity="center"
android:background="#drawable/selectable_day_layout_border"/>
<com.gp.app.minote.calendar.ui.CalendarGridView
android:layout_width="30dip"
android:layout_height="40dip"
android:id="#+id/day2"
android:layout_row="2"
android:layout_column="1"
android:layout_margin="2dip"
android:padding="3dip"
android:layout_gravity="center"
android:background="#drawable/selectable_day_layout_border"/>
<com.gp.app.minote.calendar.ui.CalendarGridView
android:layout_width="30dip"
android:layout_height="40dip"
android:id="#+id/day3"
android:layout_row="2"
android:layout_column="2"
android:layout_margin="2dip"
android:layout_gravity="center"
android:padding="3dip"
android:background="#drawable/selectable_day_layout_border"/>
<!-- More CalendarGridViews but deleted for clarity -->
</GridLayout>
Below mentioned is the code from the class which extends GridLayout and uses CalendarGridViews:-
public class ProfessionalPACalendarView extends GridLayout
{
private Context context;
private Calendar cal;
private ImageButton previousMonthImageButton = null;
private ImageButton nextMonthImageButton = null;
private TextView monthNameTextView = null;
private List<DateInformation> dateList = new ArrayList<>();
private List<CalendarGridView> calendarGrids = new ArrayList<>();
private RelativeLayout base;
private ImageView next,prev;
private boolean isWithoutEvents = false;
private int id = 0;
public ProfessionalPACalendarView(Context context)
{
super(context);
this.context = context;
cal= Calendar.getInstance();
if(!isWithoutEvents)
{
CalendarDBManager.getInstance().addDataChangeListener(this);
}
initView();
this.isWithoutEvents = isWithoutEvents;
}
public ProfessionalPACalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
initView();
}
public ProfessionalPACalendarView(Context context, AttributeSet attrs,int defStyle)
{
super(context, attrs, defStyle);
this.context = context;
initView();
}
private void initView()
{
init();
Calendar calendar = Calendar.getInstance();
refreshDays(calendar.get(Calendar.DATE), calendar.get(Calendar.MONTH), calendar.get(Calendar.YEAR));
fillCalendarViewWithDates();
}
private void init()
{
int id = (int)Math.abs(Math.random() * 100000);
super.setId(id);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.calendar_grid_layout, null);
addView(view);
previousMonthImageButton = (ImageButton) findViewById(R.id.previousMonthImageButton);
previousMonthImageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
previousMonth();
}
});
monthNameTextView = (TextView) findViewById(R.id.monthNameTextView);
nextMonthImageButton = (ImageButton) findViewById(R.id.nextMonthImageButton);
nextMonthImageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
nextMonth();
}
});
calendarGrids.add((CalendarGridView) findViewById(R.id.day2));
calendarGrids.add((CalendarGridView) findViewById(R.id.day3));
}
Problem :- findViewById(id) in the lines below :-
previousMonthImageButton =(ImageButton)findViewById(R.id.previousMonthImageButton);
monthNameTextView = (TextView) findViewById(R.id.monthNameTextView);
nextMonthImageButton = (ImageButton) findViewById(R.id.nextMonthImageButton);
returns non null value whereas findViewById(id) in the below lines:-
calendarGrids.add((CalendarGridView) findViewById(R.id.day2));
calendarGrids.add((CalendarGridView) findViewById(R.id.day3));
return null value.
I have trying to solve this problem for long but not getting the difference why same method returns null and non null value for different views. I think this has something to do with composite views. Please help.
You initialize View view = inflater.inflate(R.layout.calendar_grid_layout, null);
Please pass View Object .
previousMonthImageButton =(ImageButton)view.findViewById(R.id.previousMonthImageButton);
monthNameTextView = (TextView)view. findViewById(R.id.monthNameTextView);
nextMonthImageButton = (ImageButton)view.findViewById(R.id.nextMonthImageButton);
Try this way .I hope it will helps you .

What else do I need to call my compound control?

I have created a compound control with the following:
Java
public class QuantityBox extends LinearLayout
{
private TextView partNmbr;
private Button decrease;
private Button increase;
private EditText quantity;
private int qty;
public QuantityBox(Context context)
{
super(context);
// load views
loadViews();
}
/**
* This constructor is necessary in order to use this compound
* control in an XML layout.
* #param context Application context
* #param attrs
*/
public QuantityBox(Context context, AttributeSet attrs)
{
super(context, attrs);
// inflate the view we created
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.quantity_box, this);
// load views
loadViews();
}
/**
* Load the views created from the constructor
*/
private void loadViews()
{
this.qty = 1;
partNmbr = (TextView) findViewById(R.id.tvPartNmbr);
decrease = (Button) findViewById(R.id.btnDecrease);
increase = (Button) findViewById(R.id.btnIncrease);
quantity = (EditText) findViewById(R.id.etQty);
// set initial text
quantity.setText(this.qty);
decrease.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// decrease quantity
qty--;
// update view
quantity.setText(qty);
}
});
increase.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// increase quantity
qty++;
// update view
quantity.setText(qty);
}
});
}
}
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="match_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/tvPartNmbr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
/>
<Button
android:id="#+id/btnDecrease"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:text="-"
/>
<EditText
android:id="#+id/etQty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
/>
<Button
android:id="#+id/btnIncrease"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:text="+"
/>
</LinearLayout>
And I trying to create it here, programmatic-ally:
public class CustomHeaderActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_title_bar);
QuantityBox qb = new QuantityBox(this);
}
}
Why isn't this working? Am I missing a step? (NullPointerException is thrown.)
The widgets will not be there by the time you call loadViews(). Wait for that until onFinishInflate().
You never inflate your view in the constructor that only takes the Context argument, meaning quantity.setText(...); will throw a NPE because quantity wasn't found in findViewById(...);

Categories

Resources