I'm trying to implement a custom ProgressBarPreference, adding at the bottom of a default preference a ProgressBar and a TextView, and granting the methods of the progressbar like setProgress() or setMax() for changing it. Here's my code works except the updating the progress within onCreate or onResume for example, how can I allow to set the progress in those points ? (actually is giving a null pointer exception over mProgressBar):
ProgressBarPreference.java
public class ProgressBarPreference extends Preference {
public ProgressBarPreference(Context context) {
super(context);
}
public ProgressBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ProgressBarPreference(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
ProgressBar mProgressBar;
#Override
protected View onCreateView(ViewGroup parent) {
LayoutInflater li = (LayoutInflater) Manager.appcontext.getSystemService(Service.LAYOUT_INFLATER_SERVICE);
View myLayout=li.inflate(R.layout.progressbarpreference, null, false);
((ViewGroup)myLayout.findViewById(R.id.preference_super_container)).addView(super.onCreateView(parent));
mProgressBar=(ProgressBar) myLayout.findViewById(R.id.preference_progress_bar);
return myLayout;
}
public void setProgress(int value){
mProgressBar.setProgress(value);
}
}
progressbarpreference.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:id="#+id/preference_super_container"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical"
></LinearLayout>
<RelativeLayout
android:id="#+id/relativeLayout1"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:paddingLeft="20sp"
android:paddingRight="20sp"
>
<TextView
android:layout_alignParentRight="true"
android:text="0 new of 100"
android:id="#+id/preference_progress_label"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:gravity="center"
android:layout_centerVertical="true"
android:paddingLeft="15sp"
android:textColor="#FFFFFF"
></TextView>
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/preference_progress_bar"
android:layout_centerVertical="true"
android:progress="50"
android:layout_toLeftOf="#id/preference_progress_label"
android:layout_alignParentLeft="true"
></ProgressBar>
</RelativeLayout>
</LinearLayout>
Ok have a solution (Android does it with an OnPreferenceChangeInternalListener but this is an easy working solution)
public class ProgressBarPreference extends Preference {
public ProgressBarPreference(Context context) {
super(context);
}
public ProgressBarPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ProgressBarPreference(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
private ProgressBar mProgressBar;
private TextView mLabel;
private int lastReqProgress=-1;
private int lastReqMax=-1;
private String lastLabel;
#Override
protected View onCreateView(ViewGroup parent) {
LayoutInflater li = (LayoutInflater) Manager.appcontext.getSystemService(Service.LAYOUT_INFLATER_SERVICE);
View myLayout=li.inflate(R.layout.progressbarpreference, null, false);
((ViewGroup)myLayout.findViewById(R.id.preference_super_container)).addView(super.onCreateView(parent));
mProgressBar=(ProgressBar) myLayout.findViewById(R.id.preference_progress_bar);
mLabel=(TextView) myLayout.findViewById(R.id.preference_progress_label);
if (lastReqProgress>-1){
mProgressBar.setProgress(lastReqProgress);
}
if (lastReqMax>-1){
mProgressBar.setMax(lastReqMax);
}
if (lastLabel!=null){
mLabel.setText(lastLabel);
}
return myLayout;
}
public void setProgress(int value){
if (mProgressBar!=null){
mProgressBar.setProgress(value);
} else {
lastReqProgress=value;
}
}
public void setMax(int value){
if (mProgressBar!=null){
int savedprogress=mProgressBar.getProgress();
mProgressBar.setMax(0);
mProgressBar.setMax(value);
mProgressBar.setProgress(savedprogress);
} else {
lastReqMax=value;
}
}
public void setLabel(String text){
if (lastLabel!=null){
mLabel.setText(text);
} else {
lastLabel=text;
}
}
}
Related
I'm trying to set 'Sub-title' of a CollapsingToolbarLayout in my app using this example here.
Here's the code from onCreate() of Profile.java:
CollapsingToolbarLayout collapsingToolbarLayout;
Toolbar toolbar;
HeaderView toolbarHeaderView;
HeaderView floatHeaderView;
collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapse_toolbar);
// error on the line below
toolbarHeaderView = (HeaderView) findViewById(R.id.toolbar_header_view);
floatHeaderView = (HeaderView) findViewById(R.id.float_header_view);
toolbarHeaderView.bindTo("title", "subtitle");
floatHeaderView.bindTo("title", "subtitle");
Here's activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinatorLayout"
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:fitsSystemWindows="true"
tools:context="com.abc.zzz.Profile">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="256dp"
android:theme="#style/AppTheme.AppBarOverlay"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapse_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="#color/colorPrimary"
android:fitsSystemWindows="true"
app:popupTheme="#style/AppTheme.PopupOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="parallax">
<include
android:id="#+id/toolbar_header_view"
layout="#layout/header_view"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginRight="#dimen/header_view_end_margin_right"
android:layout_marginEnd="#dimen/header_view_end_margin_right"
android:visibility="gone"
/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<include
android:id="#+id/float_header_view"
layout="#layout/header_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.abc.zzz.ViewBehavior"/>
</android.support.design.widget.CoordinatorLayout>
Here's header_view.xml:
<?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">
<!-- Title -->
<TextView
android:id="#+id/header_view_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#android:color/white"
android:textSize="18sp"
/>
<!-- Subtitle -->
<TextView
android:id="#+id/header_view_sub_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#android:color/white"
android:textSize="16sp"
/>
</LinearLayout>
Here's HeaderView.java:
public class HeaderView extends LinearLayout {
TextView title;
TextView subTitle;
public HeaderView(Context context) {
super(context);
}
public HeaderView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public HeaderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
title = (TextView) findViewById(R.id.header_view_title);
subTitle = (TextView) findViewById(R.id.header_view_sub_title);
}
public void bindTo(String title) {
bindTo(title, "");
}
public void bindTo(String title, String subTitle) {
hideOrSetText(this.title, title);
hideOrSetText(this.subTitle, subTitle);
}
private void hideOrSetText(TextView tv, String text) {
if (text == null || text.equals(""))
tv.setVisibility(GONE);
else
tv.setText(text);
}
}
Here's ViewBehavior.java:
public class ViewBehavior extends CoordinatorLayout.Behavior<HeaderView> {
private Context mContext;
private int mStartMarginLeft;
private int mEndMargintLeft;
private int mMarginRight;
private int mStartMarginBottom;
private boolean isHide;
public ViewBehavior(Context context, AttributeSet attrs) {
mContext = context;
}
#Override
public boolean layoutDependsOn(CoordinatorLayout parent, HeaderView child, View dependency) {
return dependency instanceof AppBarLayout;
}
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent, HeaderView child, View dependency) {
shouldInitProperties(child, dependency);
int maxScroll = ((AppBarLayout) dependency).getTotalScrollRange();
float percentage = Math.abs(dependency.getY()) / (float) maxScroll;
float childPosition = dependency.getHeight()
+ dependency.getY()
- child.getHeight()
- (getToolbarHeight() - child.getHeight()) * percentage / 2;
childPosition = childPosition - mStartMarginBottom * (1f - percentage);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
lp.leftMargin = (int) (percentage * mEndMargintLeft) + mStartMarginLeft;
lp.rightMargin = mMarginRight;
child.setLayoutParams(lp);
child.setY(childPosition);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (isHide && percentage < 1) {
child.setVisibility(View.VISIBLE);
isHide = false;
} else if (!isHide && percentage == 1) {
child.setVisibility(View.GONE);
isHide = true;
}
}
return true;
}
private void shouldInitProperties(HeaderView child, View dependency) {
if (mStartMarginLeft == 0)
mStartMarginLeft = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_start_margin_left);
if (mEndMargintLeft == 0)
mEndMargintLeft = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_end_margin_left);
if (mStartMarginBottom == 0)
mStartMarginBottom = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_start_margin_bottom);
if (mMarginRight == 0)
mMarginRight = mContext.getResources().getDimensionPixelOffset(R.dimen.header_view_end_margin_right);
}
public int getToolbarHeight() {
int result = 0;
TypedValue tv = new TypedValue();
if (mContext.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
result = TypedValue.complexToDimensionPixelSize(tv.data, mContext.getResources().getDisplayMetrics());
}
return result;
}
}
The problem is that I'm getting this error: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.abc.zzz/com.abc.zzz.Profile}: java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to com.abc.zzz.HeaderView on the line specified above.
Why am I getting this error and how to resolve it?
Please let me know.
You didn't show on your code but I bet that your header_view.xml have a LinearLayout as the root view.
So basically what happens is: the <include code "gets replaced" by the LinearLayout at the root of header_view.xml and then you call findViewById(R.id.toolbar_header_view) which returns that LinearLayout and then with the (HeaderView) you're telling the VM this is a HeaderView, but it's, it's a LinearLayout. So it crashes!
The best option without seeing piece of code you didn't show it is one of the following:
put <HeaderView> at the root of header_view.xml,
or if that is not possible because there's more stuff inside header_view.xml
change your code to find the include and then inside the include, to find the actual HeaderView.
Something like:
toolbarHeaderView = (HeaderView) findViewById(R.id.toolbar_header_view).findViewById(R.id.header_view_id);
floatHeaderView = (HeaderView) findViewById(R.id.float_header_view).findViewById(R.id.header_view_id);
note that it calls findViewById two times. One for the include and another for the HeaderView inside it
I'm trying to figure out why an Android custom view which works when no background is set suddenly stops working when the background is set. It seems the background covers the items added to the view when it is set. I've simplified the view code to the bare minimum which reproduces the problem and to be able to post the code here. The custom view inherits from RelativeLayout and the code is as follow:
public class TestView extends RelativeLayout {
private LayoutInflater mInflater;
private ViewTreeObserver mViewTreeObserber;
private boolean mInitialized = false;
public TestView(Context ctx) {
super(ctx, null);
initialize(ctx, null, 0);
}
public TestView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
initialize(ctx, attrs, 0);
}
public TestView(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
initialize(ctx, attrs, defStyle);
}
private void initialize(Context ctx, AttributeSet attrs, int defStyle) {
mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mViewTreeObserber = getViewTreeObserver();
mViewTreeObserber.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!mInitialized) {
mInitialized = true;
drawItem();
}
}
});
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawItem();
}
private void drawItem() {
if (!mInitialized) return;
removeAllViews();
View item = mInflater.inflate(R.layout.testview_item, null);
TextView txt = (TextView)item.findViewById(R.id.test_view_item);
txt.setText("Test View Text");
txt.setTextColor(Color.BLACK);
txt.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
addView(item);
}
}
The item layout is simple:
<?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_vertical"
android:orientation="horizontal" >
<TextView
android:id="#+id/test_view_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:ellipsize="end"
android:maxLines="1" />
</LinearLayout>
And the sample app simply declares two instances of the custom view in XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin">
<TextView android:text="With Background set"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.machado.felipe.TestView
android:background="#android:color/holo_blue_light"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.machado.felipe.TestView>
<TextView android:text="WithOUT Background set"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.machado.felipe.TestView
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.machado.felipe.TestView>
</LinearLayout>
The result looks like the picture bellow:
This is driving me crazy! I'm not used to write custom views in android and this is someone else's code which I'm trying to fix! I don't even know if this is the way it should be done, since I'm inflating views and adding them to the RelativeLayout I don't think I should be adding them in the onDraw, but since the complete code is doing more complex stuff, as laying out the items in multiple rows with wrapping, it is possibly a valid approach... But, anyway, I can't figure out how to fix this!
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);
}
}
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 .
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);
}
}