How to initialize stuff that depends on the view’s attributes - android

Say I have this class MyView:
public class MyView extends GLSurfaceView {
private MyRenderer mRenderer;
public MyView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
init(ctx);
}
private void init(Context ctx) {
mRenderer = new MyRenderer(ctx);
setRenderer(mRenderer);
}
#Override
public void setBackground(Drawable background) {
mRenderer.setBackground(background);
}
}
That is inflated by MyActivity like this:
public class MyActivity extends Activity {
private MyView mView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
protected void init() {
setContentView(R.layout.my_layout);
mView = (MyView) findViewById(R.id.my_view);
}
}
To my knowledge setBackground is called by the inflater in setContentView, before init is called in MyView, so mRenderer has not been initialized yet.
It seems like a catch 22, because the view's attributes can't be set without the view's initialization, which happens after the attributes are set.
This is the layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#drawable/background" >
<com.developer.app.MyView
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/background"
/>
<TextView
android:id="#+id/left_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="#drawable/left_arrow"
/>
<TextView
android:id="#+id/right_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="#drawable/right_arrow"
/>
<TextView
android:id="#+id/home_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:background="#drawable/home"
/>
</RelativeLayout>

You are right. setBackground() is called from View's constructor if android:background attribute was parsed. In your case it called here:
super(ctx, attrs);
If you want to set background to mRenderer, you can do it in init:
private void init(Context ctx) {
mRenderer = new MyRenderer(ctx);
setRenderer(mRenderer);
final Drawable background = getBackground();
if (background != null) {
mRenderer.setBackground(background);
}
}
and add a null-check in setBackground, because this method can be called from superclass' constructor before you set some value to mRenderer
#Override
public void setBackground(Drawable background) {
if (mRenderer != null) {
mRenderer.setBackground(background);
}
}

What i understood from your question. You need attributes of views in oncreate(). But unable to do so. the reason is at that point UI is not initialized yet. there is work around.
this link might help.
getWidth() and getHeight() of View returns 0

You have initialize its three functions for example and xml and java is as you are doing it.
public class MyEditText extends EditText {
public MyEditText(Context context) {
super(context);
this.setTextColor(Color.parseColor("#4789da"));
this.setBackgroundResource(R.drawable.edittext_back);
this.setTextSize(18);
this.setPadding(5,5,5,5);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
this.setTextColor(Color.parseColor("#4789da"));
this.setBackgroundResource(R.drawable.edittext_back);
this.setTextSize(18);
this.setPadding(5,5,5,5);
}
public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setTextColor(Color.parseColor("#4789da"));
this.setBackgroundResource(R.drawable.edittext_back);
this.setTextSize(18);
this.setPadding(5,5,5,5);
}
}

Related

How to add a custom view to an activity?

I know this has been asked many times on SO, but somehow I don't get to the solution reading the existing answers.
The most simple thing, I want to add a custom view in an activity.
The custom view MyView has a background color, as well as its subView.
But the activity is just plain white and does not seem to display the custom view.
Why is that?
MainAcivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
MyView myView = findViewById(R.id.myView);
}
}
main_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.myapp.MyView
android:id="#+id/myView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
MyView.java
public class MyView extends LinearLayout {
public MyView(Context context) {
super(context);
init(context);
}
public MyView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
inflate(context, R.layout.my_view, this);
subView = findViewById(R.id.subView);
//...
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
}
my_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ff00ff"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:id="#+id/subView"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="#ff00ff"
tools:ignore="ContentDescription" />
</LinearLayout>
If you don't skip onLayout implementation in you snippet then you remove layout logic of your custom view, just don't override it:
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}

Multiple layouts inside the single viewStub

I have an item which has apple, pear and lemon. I made separate layouts for apples, pears and lemons.
I want to get the layout of that element if any element is selected. I tried that put the correct layout to viewStub according to selected layout with inflate() function. But the performance of defining layouts with inflate() each time was exhausting and sometimes caused incorrect work.
Please help me.
My general view codes:
public class MyView extends RelativeLayout {
private ViewStub viewStub;
private int lemon = 1, apple = 2, pear = 3;
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
this.viewStub = ViewUtil.findById(this, R.id.view_stub);
}
public void bindElements(int type){
if (type == lemon) {castLemon(); return;}
if (type == apple ) {castApple(); return;}
if (type == pear) {castPear(); return;}
public void castLemon() {
viewStub.setLayoutResource(R.layout.lemon_item);
LemonView lemonView = (LemonView) viewStub.inflate();
}
}
public void castApple() {
viewStub.setLayoutResource(R.layout.apple_item);
AppleView appleView = (AppleView) viewStub.inflate();
}
}
public void castPear() {
viewStub.setLayoutResource(R.layout.pear_item);
PearView pearView = (PearView) viewStub.inflate();
}
}
}
My general view xml:
<com.android.android.MyView
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:id="#+id/myView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout android:id="#+id/bodyLinear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ViewStub
android:id="#+id/view_stub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:gravity="start|center_vertical"
android:paddingBottom="5dp"/>
</LinearLayout>
</com.android.android.MyView>
LemonView.java:
public class LemonView extends FrameLayout {
private ImageView imageView;
public LemonView(Context context) {
this(context, null);
}
public LemonView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LemonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.lemon_view, this);
imageView = findViewById(R.id.image);
}
lemon_view:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.android.android.LemonView">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:contentDescription="#null"
android:gravity="center"
android:scaleType="centerCrop"/>
</merge>
lemon_item xml:
<?xml version="1.0" encoding="utf-8"?>
<com.android.android.LemonView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lemon_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Create all the layouts at once, then just show / hide the needed layout variant with .setVisibility(View.VISIBLE) / .setVisibility(View.GONE).

Custom Linear Layout Child not showing

i tried to create custom linear layout that have dynamic height and width = height. The custom layout is fine, but the child view not showing at my custom linear layout. i tried some way to fix it, but still cant solve it.
public class CustomLinearLayout extends LinearLayout {
public CustomLinearLayout(Context context) {
super(context);
}
public CustomLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(height, height);
}
}
this is the xml that contain my custom linear layout. the child view not showing.
<com.example.admin.antriclient.CustomLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:autofit="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#drawable/bg_nomor_antrian"
android:padding="10dp"
>
<me.grantland.widget.AutofitTextView
android:id="#+id/service_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Teller"
android:textColor="#color/white"
android:textStyle="bold"
android:gravity="center_horizontal"
android:singleLine="false"
autofit:minTextSize="12sp"
/>
<me.grantland.widget.AutofitTextView
android:id="#+id/nomor_antrian"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="T21"
android:textSize="50sp"
android:textColor="#color/white"
android:textStyle="bold"
android:gravity="center_horizontal"
android:singleLine="true"
autofit:minTextSize="12sp"
/>
</com.example.admin.antriclient.CustomLinearLayout>
thanks in advance
My problem is because i didnt call the super.onMeasure() method. Thanks to Mike M.
my class should be like this
public class CustomLinearLayout extends LinearLayout {
public CustomLinearLayout(Context context) {
super(context);
}
public CustomLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec,heightMeasureSpec);
//int height = MeasureSpec.getSize(heightMeasureSpec);
//setMeasuredDimension(height, height);
}
}
For me I had to add a LayoutInflater for it to show
public class SidebarLayout extends LinearLayout {
private static final String TAG = "SidebarLayout";
public SidebarLayout(Context context) {
super(context);
}
public SidebarLayout(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.sidebar, this);
}
public SidebarLayout(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
<com.example.a3danimationtester.SidebarLayout
android:id="#+id/layout_sidebar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/layout_topbar" />

Android custom AutoCompleteTextView doesn't appear after hiding

I create an autoCompleteTextView as below Layout and Java class :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/autoCompleteTextViewGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:minHeight="#dimen/component_height">
<android.support.design.widget.TextInputLayout
android:id="#+id/textInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:animateLayoutChanges="true">
<AutoCompleteTextView
android:id="#+id/autoCompleteTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<android.support.v4.widget.ContentLoadingProgressBar
android:id="#+id/progressBar"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:indeterminate="true"
android:indeterminateDrawable="#anim/anim_indeterminate_mini"
android:interpolator="#anim/anim_progress_interpolator"
android:visibility="visible" />
</FrameLayout>
and Java class is :
public class MAutoCompleteText extends LinearLayout {
AutoCompleteTextView autoCompleteTextView;
ContentLoadingProgressBar progressBar;
TextInputLayout textInputLayout;
ViewGroup autoCompleteTextViewGroup;
public MAutoCompleteText(Context context) {
super(context);
init(context);
}
public MAutoCompleteText(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MAutoCompleteText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#TargetApi(21)
public MAutoCompleteText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
inflate(context, R.layout.layout_auto_complete_text, this);
autoCompleteTextViewGroup = (ViewGroup) findViewById(R.id.autoCompleteTextViewGroup);
textInputLayout = (TextInputLayout) findViewById(R.id.textInputLayout);
autoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
progressBar = (ContentLoadingProgressBar) findViewById(R.id.progressBar);
}
public void setAdapter(ArrayAdapter<String> adapter) {
autoCompleteTextView.setAdapter(adapter);
}
public String getText() {
return autoCompleteTextView.getText().toString();
}
public void setErrorEnabled(boolean status) {
textInputLayout.setErrorEnabled(status);
}
public void setError(int errorId) {
textInputLayout.setError(getContext().getString(errorId));
}
public int getVisibility() {
return autoCompleteTextViewGroup.getVisibility();
}
public void setVisibility(int visibility) {
autoCompleteTextViewGroup.setVisibility(visibility);
autoCompleteTextViewGroup.setMinimumHeight(R.dimen.component_height);
}
public void setProgressBarVisibility(int visibility) {
progressBar.setVisibility(visibility);
}
public MAutoCompleteText setHint(int hintId) {
autoCompleteTextView.setHint(hintId);
return this;
}
public void setImeOption(int imeOption) {
autoCompleteTextView.setImeOptions(imeOption);
}
}
Everything work OK. I setVisibility(GONE) and my component hide from UI,
but when I use setVisibility(VISIBLE) doesn't happen any thing !!!!
How can I display my component programmatically?
I found answer of my problem , at least it works now ... :)
I change setVisibility to below code :
public void setVisibility(int visibility) {
autoCompleteTextViewGroup.setVisibility(visibility);
if (visibility == View.VISIBLE) {
textInputLayout.setVisibility(visibility);
autoCompleteTextView.setVisibility(visibility);
progressBar.setVisibility(visibility);
requestLayout();
}
}
In fact requestLayout(); reDraw layout of my component on UI again and it`s appear correctly .

How to open An Activity by Clicking On FrameLayout?

In fact i know how to open an activity by clicking on a button
But i can't do it in frame layout
i try this code but it didn't help me.
FrameLayout ff=(FrameLayout)findViewById(R.id.btn);
ff.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(listActivity.this,bookActivity.class);
startActivity(intent);
}
});
that's all
EDITES:
this my activity_main :
<LinearLayout
android:id="#+id/linbook"
android:layout_margin="15dp"
android:layout_toRightOf="#+id/linjozve"
android:layout_width="130dp"
android:layout_height="180dp"
android:orientation="vertical">
<FrameLayout
android:id="#+id/ketabbtn"
android:layout_width="130dp"
android:layout_height="130dp">
<ImageButton
android:layout_weight="1"
android:id="#+id/btntopright"
android:layout_width="130dp"
android:layout_height="130dp"
android:background="#drawable/rgreen"/>
<ImageButton
android:background="#drawable/book"
android:layout_gravity="center"
android:layout_width="80dp"
android:layout_height="80dp" />
</FrameLayout>
<TextView
android:layout_marginTop="15dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="book"/>
</LinearLayout>
thanks
Try to set android:clickable in the xml.
If that doesn't work try to create a custom layout:
By default, onInterceptTouchEvent returns false. So include following code and use this CustomClickableFrameLayout instead of framelayout
public class CustomClickableFrameLayout extends FrameLayout {
private OnClickListener mOnClickListener;
#Override
public void setOnClickListener(OnClickListener l) {
super.setOnClickListener(l);
mOnClickListener = l;
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mOnClickListener != null;
}
// Standard constructors — just pass everything
public CustomClickableFrameLayout (final Context context) {
super(context);
}
public CustomClickableFrameLayout (final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public CustomClickableFrameLayout (final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomClickableFrameLayout (final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
}
The problem is it is quite hard to click on a FrameLayout if it is covered by other views. In your case, the framelayout and the imagebutton have the same size 130x130. This explains why the touch cannot reach the layout.
To make sure you can click it, add some padding between the layout and its childs. (I reduced the size of its child)
<FrameLayout
android:padding="10dp"
android:id="#+id/ketabbtn"
android:layout_width="130dp"
android:layout_height="130dp">
<ImageButton
android:layout_weight="1"
android:id="#+id/btntopright"
android:layout_width="120dp"
android:layout_height="120dp"
android:background="#drawable/rgreen"/>
<ImageButton
android:background="#drawable/book"
android:layout_gravity="center"
android:layout_width="80dp"
android:layout_height="80dp" />
</FrameLayout>
Also, you used wrong ID. So change this:
FrameLayout ff=(FrameLayout)findViewById(R.id.btn);
To this:
FrameLayout ff=(FrameLayout)findViewById(R.id.ketabbtn);
So you can click the padding space to trigger the onClick event.

Categories

Resources