I'm using this CheckBoxPreference Class to support RTL text direction for pre Android 4.2 versions and to use a custom font style for my preference
public class MyCheckBoxPreference extends CheckBoxPreference {
TextView txtTitle, txtSum;
View Custmv;
public MyCheckBoxPreference(Context context) {
super(context);
}
public MyCheckBoxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyCheckBoxPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onBindView(#NonNull View view) {
super.onBindView(view);
Context context = getContext();
txtTitle = (TextView) view.findViewById(android.R.id.title);
txtTitle.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Regular.ttf"));
txtSum = (TextView) view.findViewById(android.R.id.summary);
txtSum.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Regular.ttf"));
}
#Override
protected View onCreateView(ViewGroup parent) {
Context ccc = getContext();
LayoutInflater inflater = (LayoutInflater) ccc.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Custmv = inflater.inflate(R.layout.arabic_checkboxpreference_layout, parent, false);
return Custmv;
}
and I'm using it in my prefs.xml like so:
<com.app.myclasses.MyCheckBoxPreference
android:defaultValue="false"
android:key="cb_big"
android:summaryOff="#string/off"
android:summaryOn="#string/on"
android:title="#string/Show_Big_Text" />
And here is the arabic_checkboxpreference_layout.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize"
android:id="#+id/sos">
<CheckBox
android:id="#+android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:layout_marginLeft="16dip"
android:minWidth="56dp"
android:gravity="center"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="16dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1"
android:gravity="end">
<TextView
android:id="#+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:textColor="?android:attr/textColorPrimary"
android:text="Title"
android:layout_alignParentRight="true" />
<TextView
android:id="#android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#android:id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:maxLines="3"
android:text="subTitle"
android:layout_alignRight="#android:id/title"
android:textColor="?android:attr/textColorSecondary" />
</RelativeLayout>
Every thing works great, but the problem is when using more than one instance of my custom class, I mean when using multiple CheckBoxPreferences in prefs.xml and when clicking on a CheckBoxPreference it becomes focused for a while (~ 1-2 seconds) before getting checked or unchecked.
Any idea please?
Edit:
According to kha answer I removed the initialization from the onBind method to the constructor and every thing is smooth now:
public MyCheckBoxPreference(Context context, AttributeSet attrs) {
super(context, attrs);
this.mTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Regular.ttf");
this.Custmv = View.inflate(context, R.layout.arabic_checkboxpreference_layout, null);
TextView txtTitle = (TextView) Custmv.findViewById(android.R.id.title);
txtTitle.setTypeface(mTypeface);
TextView txtSum = (TextView) Custmv.findViewById(android.R.id.summary);
txtSum.setTypeface(mTypeface);
}
It may be related to the fact you load the font with Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Regular.ttf")every time you're binding the view.
Try moving it out from your onBindView method and create it once in your view instead and use the reference when you need to set the font and see if that makes any difference
Related
I have an activity loaded from XML, with views having IDs as usual:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="80dp"
android:layout_height="110dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/white_circle">
<com.myapp.views.CircleImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="16dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="-12dp"
android:background="#drawable/price_background">
<TextView
android:id="#+id/priceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:text="0.1 BTC"
android:textAllCaps="true"
android:textColor="#color/white"
android:textSize="10sp"
android:textStyle="bold" />
</FrameLayout>
<TextView
android:id="#+id/nameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_horizontal"
android:lineSpacingMultiplier="0.8"
android:lines="2"
android:text="Bacon Cheeseburger"
android:textSize="10sp" />
</LinearLayout>
</FrameLayout>
I'm trying to reference three views in code:
public ItemViewHolder(View itemView) {
super(itemView);
nameView = itemView.findViewById(R.id.nameView);
priceView = itemView.findViewById(R.id.priceView);
imageView = itemView.findViewById(R.id.imageView);
}
nameView and priceView are referenced correctly, however, imageView isn't being referenced and is null:
Why can't I reference imageView?
(If I traverse the view tree, it is there.)
UPDATE: I did both Clean Project and Invalidate Caches/Restart, the problem persists.
UPDATE 2: ItemViewHolder is derived from RecyclerView.ViewHolder. CircleImageView is derived from FrameLayout (not ImageView). This XML is the layout of my view holder.
UPDATE 3: Here is my circle view's constructor:
public class CircleImageView extends FrameLayout {
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context);
init();
}
public CircleImageView(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
...
}
Also, as Subzero noted, I've checked the ID property (mID field) of the view, and it's -1, which seems to be the cause of the problem. I have no idea why it is -1 though.
Change the super call in your two-parameter constructor to:
super(context, attrs);
When a View is inflated from a layout, the XML attributes and their values are passed into the two-parameter constructor via the AttributeSet. If you don't pass that to the superclass, the id you've specified in the XML is never set on the View, so findViewById() won't find it with the given ID.
I like Use this as follows, hope it is helpful.
public class CircleImageView extends FrameLayout {
public CircleImageView(Context context) {
this(context,null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context.attrs,0);
}
public CircleImageView(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
...
}
I think the problem is, that your imageView in layout.xml is a custom view (com.myapp.views.CircleImageView), not a regular android ImageView.
Try cast to ImageView, if the class extends imageview
ImageView iv = (ImageView) itemView.findViewById(R.id.imageView));
or use it as your custom view
CircleImageView iv = (CircleImageView) itemView.findViewById(R.id.imageView));
I have an activity loaded from XML, with views having IDs as usual:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="80dp"
android:layout_height="110dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_horizontal"
android:background="#drawable/white_circle">
<com.myapp.views.CircleImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="16dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="-12dp"
android:background="#drawable/price_background">
<TextView
android:id="#+id/priceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:text="0.1 BTC"
android:textAllCaps="true"
android:textColor="#color/white"
android:textSize="10sp"
android:textStyle="bold" />
</FrameLayout>
<TextView
android:id="#+id/nameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="center_horizontal"
android:lineSpacingMultiplier="0.8"
android:lines="2"
android:text="Bacon Cheeseburger"
android:textSize="10sp" />
</LinearLayout>
</FrameLayout>
I'm trying to reference three views in code:
public ItemViewHolder(View itemView) {
super(itemView);
nameView = itemView.findViewById(R.id.nameView);
priceView = itemView.findViewById(R.id.priceView);
imageView = itemView.findViewById(R.id.imageView);
}
nameView and priceView are referenced correctly, however, imageView isn't being referenced and is null:
Why can't I reference imageView?
(If I traverse the view tree, it is there.)
UPDATE: I did both Clean Project and Invalidate Caches/Restart, the problem persists.
UPDATE 2: ItemViewHolder is derived from RecyclerView.ViewHolder. CircleImageView is derived from FrameLayout (not ImageView). This XML is the layout of my view holder.
UPDATE 3: Here is my circle view's constructor:
public class CircleImageView extends FrameLayout {
public CircleImageView(Context context) {
super(context);
init();
}
public CircleImageView(Context context, AttributeSet attrs) {
super(context);
init();
}
public CircleImageView(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
...
}
Also, as Subzero noted, I've checked the ID property (mID field) of the view, and it's -1, which seems to be the cause of the problem. I have no idea why it is -1 though.
Change the super call in your two-parameter constructor to:
super(context, attrs);
When a View is inflated from a layout, the XML attributes and their values are passed into the two-parameter constructor via the AttributeSet. If you don't pass that to the superclass, the id you've specified in the XML is never set on the View, so findViewById() won't find it with the given ID.
I like Use this as follows, hope it is helpful.
public class CircleImageView extends FrameLayout {
public CircleImageView(Context context) {
this(context,null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context.attrs,0);
}
public CircleImageView(#NonNull Context context, #Nullable AttributeSet attrs, #AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
...
}
I think the problem is, that your imageView in layout.xml is a custom view (com.myapp.views.CircleImageView), not a regular android ImageView.
Try cast to ImageView, if the class extends imageview
ImageView iv = (ImageView) itemView.findViewById(R.id.imageView));
or use it as your custom view
CircleImageView iv = (CircleImageView) itemView.findViewById(R.id.imageView));
Hopefully this question will resolve to me having incorrect expectations, but I'm using Android Studio 0.2.10 and am having problems with the rendering system recognizing the XML for a custom view group extending RelativeLayout as an actual RelativeLayout. The effects of this are that children in the custom view aren't getting options that should be available to them... layout_width, layout_height or alignComponent for instance (which seems to indicate that it's not even recognizing the custom layout as a layout at all).
I can of course just add these attributes to the XML manually or just set the root tag to RelativeLayout temporarily and the design tool seems to work fine, but I'm curious if, because AndroidStudio is failing to resolve the custom extension properly, I'm doing something wrong by design. I'm new to Android development, so I didn't want to lob this away as an IDE bug prematurely.
public class CommentCellView extends RelativeLayout {
private static String TAG = "CommentCellView";
final private CommentCellView _cellView;
private Comment _comment;
public CommentCellView(Context context) {
super(context);
_cellView = this;
}
public CommentCellView(Context context, AttributeSet attrs) {
super(context, attrs);
_cellView = this;
}
public CommentCellView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
_cellView = this;
}
public void setComment(Comment comment) {
_comment = comment;
TextView nameTextView = (TextView)this.findViewById(R.id.commentcell_nameTextView);
TextView commentTextView = (TextView)this.findViewById(R.id.commentcell_commentTextView);
TextView dateTextView = (TextView)this.findViewById(R.id.commentcell_dateTextView);
nameTextView.setText(comment.name);
commentTextView.setText(comment.comment);
dateTextView.setText(comment.date);
}
}
<com.testapp.CommentCellView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#ffffff">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/commentcell_backgroundImageView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:src="#drawable/comment_bg"/>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/commentcell_avatarImageView"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:src="#drawable/avatar"
android:layout_marginLeft="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/commentcell_nameTextView"
android:layout_alignTop="#+id/commentcell_avatarImageView"
android:layout_toRightOf="#+id/commentcell_avatarImageView"
android:layout_marginLeft="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:id="#+id/commentcell_commentTextView"
android:layout_below="#+id/commentcell_nameTextView"
android:layout_alignLeft="#+id/commentcell_nameTextView"
android:textColor="#999999"
android:layout_marginTop="2dp"
android:layout_alignParentRight="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/commentcell_dateTextView"
android:layout_alignBottom="#+id/commentcell_avatarImageView"
android:layout_toRightOf="#+id/commentcell_avatarImageView"
android:layout_marginLeft="10dp"/>
</com.testapp.CommentCellView>
I'm getting a null pointer exception in my custom view (which is derived from a LinearLayout) because it can't find its child views. Here is the code:
public class MyView extends LinearLayout
{
public MyView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public MyView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
private TextView mText;
#Override
protected void onFinishInflate()
{
super.onFinishInflate();
mText = (TextView) findViewById(R.id.text);
if (isInEditMode())
{
mText.setText("Some example text.");
}
}
}
Here is the layout (my_view.xml):
<?xml version="1.0" encoding="utf-8"?>
<com.example.views.MyView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:ellipsize="end"
android:maxLines="4"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="Some text" />
</com.example.views.MyView>
And here is how I put it in the XML file:
<com.example.views.MyView
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
But when I try to preview it in the layout editor I get an NPE on mText.setText(...) because getViewById() returns null.
What's going on?
Clarification
The reason I expect this to work, is if I do
MyView v = (MyView)inflater.inflate(R.layout.my_view);
((TextView)v.findViewById(R.id.text)).setText("Foo");
everything works fine. Is that not what the layout inflater does when it goes through a layout file? In any case, how can I handle both situations correctly (without getting pointless nested views)?
In you XML file you are trying to use a custom view class (com.example.views.MyView) and in the same time trying to add a TextView inside. It's not possible.
Here is what you need to change:
You must inflate XML file in the code:
public MyView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.<your_layout>.xml, this);
}
And modify the XML layout file like this:
<?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="horizontal" >
<TextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:ellipsize="end"
android:maxLines="4"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:text="Some text" />
</LinearLayout>
I have a custom "view" widget (CustomController) on my application's main screen.
In the widget's constructor, I can access an image in the widget's xml file with the following code:
(Note, img_cursor is an ImageView in "custom_controller.xml")
public final class CustomController extends LinearLayout{
public CustomController(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view_controller = layoutInflater.inflate(R.layout.custom_controller,this);
img_cursor = (ImageView) view_dpad.findViewById(R.id.img_cursor);
...
However, I want to access a TextView on the main activity's screen.
The custom controller widget is displayed on the main screen through main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linlayRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.test.projectname.CustomController
android:id="#+id/dpad"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="15px"
android:layout_marginLeft="15px" />
<Button
android:text="Connect"
android:id="#+id/btn_connection"
android:layout_height="wrap_content"
android:layout_width="100dp">
</Button>
<Button
android:text="Settings"
android:id="#+id/btn_settings"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
</Button>
<Button
android:text="Debug x,y"
android:layout_width="wrap_content"
android:id="#+id/btn_debug_x_y"
android:layout_height="wrap_content">
</Button>
<TextView
android:id="#+id/txt_view_x"
android:layout_marginLeft="20dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="X = 0">
</TextView>
<TextView
android:id="#+id/txt_view_y"
android:layout_marginLeft="20dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Y = 0">
</TextView>
</LinearLayout>
How do I access the TextViews in main.xml from the CustomController class?
I've tried stuff like:
public final class CustomController extends LinearLayout{
public CustomController(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View main_controller = layoutInflater.inflate(R.layout.main,this);
textview = (TextView) view_dpad.findViewById(R.id.txt_view_x);
...
I can't seem to access the main screen's view. It doesn't like:
View main_controller = layoutInflater.inflate(R.layout.main,this);
Thanks for any help!