compound layout doesn't show inner views - android

I extended from LinearLayout and inflated views, but on the screen those views in my layout are not appeared. I see my view group in editor, but it seems like it's empty. No views inside it.
FragmentPickerViewGroup looks like this:
package com.test.pecode.myapplication;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class FragmentPickerViewGroup extends LinearLayout {
private ImageView background;
private Button minusButton;
private Button plusButton;
public FragmentPickerViewGroup(Context context) {
super(context);
init();
}
private void init() {
setOrientation(LinearLayout.HORIZONTAL);
inflate(getContext(), R.layout.view_fragment_picker, this);
minusButton = findViewById(R.id.minus_btn);
plusButton = findViewById(R.id.plus_btn);
background = findViewById(R.id.background_rectangle);
minusButton.setVisibility(INVISIBLE);
minusButton.setGravity(Gravity.TOP | Gravity.START);
minusButton.setBackgroundResource(R.mipmap.button_bg);
background.setBackgroundResource(R.mipmap.rectangle);
background.setBackgroundResource(R.mipmap.rectangle);
plusButton.setBackgroundResource(R.mipmap.button_bg);
plusButton.setGravity(Gravity.TOP | Gravity.END);
}
public FragmentPickerViewGroup(Context context, #Nullable AttributeSet
attrs) {
super(context, attrs);
init();
}
public FragmentPickerViewGroup(Context context, #Nullable AttributeSet
attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public FragmentPickerViewGroup(Context context, AttributeSet attrs, int
defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
}
I used merge tag for my layout. Probably something goes wrong there? This is my layout, which I inflate into my view group:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/minus_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="#+id/background_rectangle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|top"
android:contentDescription="#string/background_rectangle" />
<Button
android:id="#+id/plus_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</merge>

Related

Custom view (not ViewGroup) created based on xml layout (with predefined attributes)

I want to implement a custom ImageView with some predefined attributes based on the xml file. To do that I prepared a layout wrapped within merge tag:
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/my_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="#drawable/icon" />
</merge>
And extended ImageView class:
public class CustomImageView extends LinearLayout{
public ImageFormField(Context context) {
super(context);
init();
}
public ImageFormField(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ImageFormField(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ImageFormField(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
View.inflate(getContext(), R.layout.custom_image_view, this);
}
}
It works so far, but I actually don't need that LinearLayout as I could extend directly from the ImageView. By extending ImageView I'd like to have the possibility to override src parameter from the default layout.
So I removed merge tag to have only ImageView in the layout and tried this:
public class CustomImageView extends AppCompatImageView{
public ImageFormField(Context context) {
super(context);
init();
}
public ImageFormField(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ImageFormField(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
View.inflate(getContext(), R.layout.custom_image_view, null); //can't pass root here
}
}
... but the image is simply not displayed. I want to be able to use my view this way:
<com.my.package.CustomImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
with possibility to override src attribute. Is there a way to do that by inflating layout or do I have to go deep with attributes (including custom ones)?
UPDATE
By "overriding src attribute I mean that by default image will have source from its xml file, but user can use it that way to pass another value within this custom view:
<com.my.package.CustomImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/another_icon" />
To provide a "default" image but also allow the user to override that default by specifying the android:src attribute, you can do this:
package com.example.stackoverflow;
import android.content.Context;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
public class CustomImageView extends AppCompatImageView {
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
if (getDrawable() == null) {
setImageResource(R.drawable.default_image);
}
}
}
Then you can use it like this:
<!-- will display `default_image` -->
<com.example.stackoverflow.CustomImageView
android:layout_width="200dp"
android:layout_height="200dp"/>
Or:
<!-- will display `other_image` -->
<com.example.stackoverflow.CustomImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="#drawable/other_image"/>
There's no need to inflate anything inside the custom image view, and no need to create custom attributes (though you could certainly create custom attributes and use them if you wanted to).
You could update the Java code to apply other "default" styles too.

Error: android.view.inflateExeption in CustomTextView

I have a menu activity that gets user setting of font and size and line spacing of text in all of TextView's, so i need a CustomTextView class to set these changes but my custom TextView does't work and give inflate Exception in logcat window. tank's a lot for your helps!
my CustomTextView:
package com.niloo.test2;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
public class CustomTextView extends TextView {
Context context;
SharedPreferences shp = context.getSharedPreferences("text", Context.MODE_PRIVATE);
int size = shp.getInt("size", 22);
int fasle = shp.getInt("fasle", 1);
String font = shp.getString("font", "bmitra");
public CustomTextView(Context context) {
super(context);
if (!isInEditMode())
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/"+font));
setTextSize(size);
setLineSpacing(fasle, 1);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if (! isInEditMode())
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/"+font));
setTextSize(size);
setLineSpacing(fasle, 1);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (!isInEditMode())
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/"+font));
setTextSize(size);
setLineSpacing(fasle, 1);
}
protected void onDraw (Canvas canvas) {
super.onDraw(canvas);
}
}
my XML code:
<com.niloo.test2.CustomTextView
android:id="#+id/tv_onv_amoozsh"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_marginTop="10dp"
android:layout_weight="0.5"
android:textColor="#color/sabz_lajani"
android:textSize="25sp"
android:textStyle="bold" />
<com.niloo.test2.CustomTextView
android:id="#+id/tv_num_amoozsh"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_marginBottom="2dp"
android:layout_weight="0.75"
android:textColor="#color/sabz_lajani"
android:textSize="35sp" />
and my main class:
final CustomTextView tv_onv_amoozsh= (CustomTextView) findViewById(R.id.tv_onv_amoozsh);
tv_onv_amoozsh.setText("page");
final CustomTextView tv_num_amoozsh=(CustomTextView) findViewById(R.id.tv_num_amoozsh);
tv_num_amoozsh.setText(sfhe_num);
LogCat Error:
02-03 22:41:38.329: E/AndroidRuntime(19952): FATAL EXCEPTION: main
02-03 22:41:38.329: E/AndroidRuntime(19952): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.niloo.test2/com.niloo.test2.MainActivity}: android.view.InflateException: Binary XML file line #143: Error inflating class com.niloo.test2.CustomTextView
The problem is most likely that you're initializing shp, size, fasle, and font outside of the constructor. These initializations happen before any constructor code is run. context is never set and is null when getSharedPreferences is called on it.
Try this:
public class CustomTextView extends TextView {
private SharedPreferences shp;
private int size;
private int fasle;
private String font;
public CustomTextView(Context context) {
super(context);
init(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
if (isInEditMode()) {
return;
}
shp = context.getSharedPreferences("text", Context.MODE_PRIVATE);
size = shp.getInt("size", 22);
fasle = shp.getInt("fasle", 1);
font = shp.getString("font", "bmitra");
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/" + font));
setTextSize(size);
setLineSpacing(fasle, 1);
}
}
Do you have this at the first view in your layout?
xmlns:custom="http://schemas.android.com/apk/res-auto"
Please post the full layout file (reduce it in your project to the minimum that is still failing. Maybe only have one view in it - your custom text )
EDIT:
The xml code you posted is invalid. Here is the fixed version that should work (do not omit "http://", remove semicolons)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/sabzabi_kmrng"
android:gravity="top"
android:orientation="vertical"
tools:context="com.niloo.test2.MainActivity">
</LinearLayout>
The error is coming from this line:
setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/"+font));
Here we don't need to mention the keyword "fonts/" for path, because getAssets() method giving the route path of assets folder. So you can directly give font name like below:
setTypeface(Typeface.createFromAsset(context.getAssets(), font));

Change color Text from CustomTextView

By default to change textColor programatically is :
textView.setTextColor(Color.RED);
I need to have a custom Textview to change typeface and color by default, How can change textcolor from CustomTextView class, here is my code.
public class CustomTextView extends TextView {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context) {
super(context);
}
public void setTypeface(Typeface tf, int style) {
if(!isInEditMode()) {
if (style == Typeface.BOLD) {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Lato-Bold.ttf"));
} else if(style == Typeface.ITALIC){ // constant used to set Lato-Light.
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Lato-Light.ttf"));
}else {
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Lato-Regular.ttf"));
}
}
}
The below code is the way to set your default text color and typeface.
public class CustomTextView extends TextView {
public CustomTextView(Context context) {
super(context);
init(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
setTypeface(Typeface.createFromAsset(context.getAssets(),"fonts/Lato-Light.ttf"));
setTextColor(Color.RED);
}
}
The init() method gets called every time the text view gets created, and will then set the typeface and color in that. You can manipulate any other variables you want to in there.
Use setTextColor(Color.RED); after each super in each constructor.
Step 1
In the /assets directory (not the /resource directory), create a folder called /fonts. Copy your custom font here. You can use both TTF and OTF fonts.
Step 2
In the /res/values folder, create a new file called attrs.xml. This is how the Android SDK lets you name custom properties for your widgets.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyTextView">
<attr name="fontName" format="string" />
</declare-styleable>
</resources>
Step 3
In /res/layouts, you will need to include your to-be-created custom text view in the activity_main.xml file.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:customfontdemo="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:padding="12dp"
android:text="Standard Android Font" />
<com.authorwjf.customfontdemo.MyTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="32sp"
android:padding="12dp"
customfontdemo:fontName="pipe_dream.ttf"
android:text="Custom Android Font" />
</LinearLayout>
Step 4
In the /src folder, you will want to create your MyTextView class. It extends the standard text view, plucks the font name from the custom attribute, and applies the type face.
package com.authorwjf.customfontdemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
public class MyTextView extends TextView {
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public MyTextView(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
setTextColor(Color.RED);
if (attrs!=null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyTextView);
String fontName = a.getString(R.styleable.MyTextView_fontName);
if (fontName!=null) {
Typeface myTypeface = Typeface.createFromAsset(getContext().getAssets(), "fonts/"+fontName);
setTypeface(myTypeface);
}
a.recycle();
}
}
}
Step 5
Because the text view is now self-contained, you aren't required to make any modifications to our /src/MainAcitivity.java file.
package com.authorwjf.customfontdemo;
import android.os.Bundle;
import android.app.Activity;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

I have a subclass of ImageView, but when I add this into XML it gives inflate error

This seems like a simple thing, but it does not run. What am I doing wrong?
I'm subclassing ImageView, but if I put it inside XML layouts, it gives:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myappSubclass/com.example.myappSubclass.MyActivity}:
android.view.InflateException: Binary XML file line #21: Error
inflating class com.example.myappSubclass.ImageViewSubclass
Here is my code:
package com.example.myappSubclass;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import java.util.jar.Attributes;
/**
* Created by me on 2014-07-11.
*/
public class ImageViewSubclass extends ImageView {
public Context thisContext;
public ImageViewSubclass(Context context, AttributeSet attrs, Context thisContext) {
super(context, attrs);
this.thisContext = thisContext;
}
public ImageViewSubclass(Context context, AttributeSet attrs, int defStyle, Context thisContext) {
super(context, attrs, defStyle);
this.thisContext = thisContext;
}
public ImageViewSubclass(Context context) {
super(context);
this.thisContext = context;
}
public void changeImage(){
this.setImageLevel(0);
}
And inside the XML I have it simply:
<?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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hello World, MyActivity"
/>
<Button android:layout_width="match_parent" android:layout_height="50dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:text="Test"
/>
<com.example.myappSubclass.ImageViewSubclass android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<!--<ImageView android:layout_width="fill_parent" android:layout_height="fill_parent"/>-->
</LinearLayout>
Custom views must have predefined constructors to be able to inflate them from an XML layout. You should remove thisContext from all of them.
public ImageViewSubclass(Context context) {
super(context);
...
}
public ImageViewSubclass(Context context, AttributeSet attrs) {
super(context, attrs);
...
}
public ImageViewSubclass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
...
}
Why did you add that extra parameter anyway? All views have a getContext() method if that's what you needed.

IDEA, Android UI Render error, null pointer

I have a problem with creating custom view. Here is code:
package com.example.App;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
public class v extends View {
public v(Context context) {
super(context);
}
public v(Context context, AttributeSet attrs) {
super(context, attrs);
}
public v(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}
I'm trying to use it in layout and getting render error(NullPointerException), here is what IDEA has jenerate in layout code:
<view android:layout_width="wrap_content"
android:layout_height="wrap_content"
class="com.example.App.v" android:id="#+id/view" android:layout_gravity="center"/>
What I'm doing wrong? How to fix it?

Categories

Resources