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).
Related
I have following CoordinatorLayout behavior :
public class FooterBarBehavior extends CoordinatorLayout.Behavior<FooterBarLayout> {
//Required to instantiate as a default behavior
public FooterBarBehavior() {
}
//Required to attach behavior via XML
public FooterBarBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
//This is called to determine which views this behavior depends on
#Override
public boolean layoutDependsOn(CoordinatorLayout parent,
FooterBarLayout child,
View dependency) {
//We are watching changes in the AppBarLayout
return getDependentView((ViewPager) dependency) instanceof AppBarLayout;
}
//This is called for each change to a dependent view
#Override
public boolean onDependentViewChanged(CoordinatorLayout parent,
FooterBarLayout child,
View dependency) {
int offset = -getDependentView((ViewPager) dependency).getTop();
child.setTranslationY(offset);
return true;
}
private View getDependentView(ViewPager viewPager) {
int index = viewPager.getCurrentItem();
MainPagerAdapter adapter = ((MainPagerAdapter)viewPager.getAdapter());
ContactsFragment fragment = (ContactsFragment) adapter.getItem(index);
if(fragment.getView() == null) {
return null;
}
return fragment.getView().findViewById(R.id.appBarLayout);
}
}
Here is FooterBarLayout :
#CoordinatorLayout.DefaultBehavior(FooterBarBehavior.class)
public class FooterBarLayout extends RelativeLayout {
public FooterBarLayout(Context context) {
super(context);
}
public FooterBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FooterBarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
It has been used in the layout as follow:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.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="wrap_content"
android:layout_height="wrap_content"
tools:context=".ui.MainActivity">
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.sample.android.contact.widget.FooterBarLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.sample.android.contact.widget.ListenableTabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:background="#drawable/rectangle_shape"
app:tabIndicatorHeight="2dp"
app:tabSelectedTextColor="#color/color1" />
<ImageView
android:id="#+id/triangle"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_above="#+id/tab_layout"
android:layout_marginBottom="#dimen/dimen_triangle_bottom_margin"
android:src="#drawable/triangle_shape"
tools:ignore="ContentDescription" />
</com.sample.android.contact.widget.FooterBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I expect that FooterBarLayout follow AppBarLayout in the fragment and hide/show based on scroll direction. The idea is taken from : https://github.com/devunwired/coordinated-effort/blob/master/app/src/main/java/com/example/android/coordinatedeffort/behaviors/FooterBarBehavior.java
But there will be no scrolling in FooterBarLayout. Do you guys have any idea to resolve this?
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);
}
}
I am trying to make a composite view by extending RelativeLayout It consists of three widgets. An ImageView , a ProgressBar and a TextView . But for some reason I am unable to see the ImageView and TextView. Attaching code below. Any suggestions?
public class ProgressView extends RelativeLayout {
#InjectView(R.id.ivItemPic)
ImageView ivItemPic;
#InjectView(R.id.tvMessage)
TextView tvMessage;
#InjectView(R.id.pbLoading)
ProgressBar pbLoading;
int defColor = 0xff669900;
public ProgressView(Context context) {
super(context);
init(context,null, 0);
}
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs, 0);
}
public ProgressView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context,attrs, defStyle);
}
public void init(Context context, AttributeSet attrs, int defStyleAttr) {
inflate(context, R.layout.component_progress_view, this);
ButterKnife.inject(this);
TypedArray aTypedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressView, defStyleAttr, 0);
final int textSize = aTypedArray.getDimensionPixelSize(
R.styleable.ProgressView_pvTextSize,
dipsToPix(R.dimen.font_medium));
final int textColor = aTypedArray.getColor(R.styleable.ProgressView_pvTextColor,defColor);
final Drawable imgSrc = aTypedArray.getDrawable(R.styleable.ProgressView_pvImageSrc);
ivItemPic.setImageDrawable(imgSrc);
tvMessage.setTextSize(textSize);
tvMessage.setTextColor(textColor);
aTypedArray.recycle();
}
/**
* Helper method to convert dips to pixels.
*/
private int dipsToPix(float dps) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dps,
getResources().getDisplayMetrics());
}
public void setText(String message) {
tvMessage.setText(message);
}
public void imageVisibility(boolean visible) {
ivItemPic.setVisibility(visible ? VISIBLE : GONE);
}
public void progressIndeterminate(boolean indeterminate) {
pbLoading.setIndeterminate(indeterminate);
}
public void setItemImage(Drawable drawable) {
ivItemPic.setImageDrawable(drawable);
}
public void setItemImageRes(int res) {
ivItemPic.setImageResource(res);
}
The XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView
android:id="#+id/ivItemPic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/pbLoading"
android:layout_centerHorizontal="true"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_marginBottom="#dimen/activity_vertical_margin"
android:src="#drawable/ic_action_info"/>
<ProgressBar
android:id="#+id/pbLoading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_marginBottom="#dimen/activity_vertical_margin"
android:layout_centerInParent="true"
style="?android:attr/progressBarStyleHorizontal"
android:indeterminate="true"
android:visibility="visible" />
<TextView
android:id="#+id/tvMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/pbLoading"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_marginRight="#dimen/horizontal_margin"
android:layout_marginLeft="#dimen/horizontal_margin"
android:textSize="#dimen/font_medium"
android:textColor="#color/grey_normal"
android:gravity="center"
android:text="Message"/>
The Layout
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:errorview="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background_color"
tools:context="com.mobility.ui.SyncFragment">
<com.mobility.customviews.SuccessView
android:id="#+id/svSuccess"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
android:gravity="center"
app:svText="Success"
app:svTextColor="#android:color/holo_green_dark"/>
<tr.xip.errorview.ErrorView
android:id="#+id/evError"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
errorview:ev_errorSubtitle="#string/err_conn"
errorview:ev_errorTitle="#string/oops"
errorview:ev_showRetryButton="true"
errorview:ev_showSubtitle="true"
errorview:ev_showTitle="true"
android:gravity="center"
android:visibility="gone"
android:paddingLeft="#dimen/horizontal_margin"
android:paddingRight="#dimen/horizontal_margin"
errorview:ev_retryButtonTextColor="#color/error_retry"/>
<com.mobility.customviews.ProgressView
android:id="#+id/progressView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:pvText="ZzZZ"/>
I want to create a ViewGroup that contains unknown number of other views as children (like LinearLayout):
<Wizard id=... width=... height=...>
<WizardStep id=... nextButtonOnClick=... preButtonOnClick=... >
<LinearLayout ...>
...
</LinearLayout>
</WIzardStep>
<WizardStep id=... nextButtonOnClick=... preButtonOnClick=... >
<RelativeLayout ...>
...
</RelativeLayout>
</WIzardStep>
<WizardStep id=... nextButtonOnClick=... preButtonOnClick=... >
...
</WIzardStep>
</Wizard>
Here Wizard and WizardStep both are ViewGroup. I don't have clue where to start. Extending ViewGroup and required functionality is all I need to do? I will appreciate any help, document, blog, etc.
This can be achieved through a ViewFlipper. If you wanted to do it programmatically, this would be a start. (NOTE: I didn't test this code, just wrote it off the top of my head)
The xml layout flip.xml
<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/flippy"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ViewFlipper>
And the activity would look something like this
public class MainActivity extends Activity{
ViewFlipper flip;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.flip);
flip = (ViewFlipper)findViewById(R.id.flip);
}
private void addViews(){
//This is where you would determine which views to add
flip.add(****** your view 1 *****)
flip.add(****** your view 2 *****)
}
You would add views whenever you were parsing the data to create them dynamically.
Then to navigate your views you can use:
flip.showNext()
flip.showPrevious()
There are more complicated things you can do with it, but that should give you the basics.
My Solution:
WizardView class:
public class WizardView extends RelativeLayout {
Context context;
private final String KEY_LAST_STEP_PASSED = "KEY_LAST_STEP_PASSED";
private final String KEY_WIZARD_FINISHED = "KEY_WIZARD_FINISHED";
private int currentStep;
private boolean isWizardFinished;
private SharedPreferences preferences;
public WizardView(Context context) {
super(context);
this.context = context;
}
public WizardView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public WizardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
public void startWizard() {
preferences = context.getSharedPreferences("wizard_pref", Context.MODE_PRIVATE);
isWizardFinished = preferences.getBoolean(KEY_WIZARD_FINISHED, false);
if (!isWizardFinished) {
currentStep = preferences.getInt(KEY_LAST_STEP_PASSED, 0);
// Make all Steps (except current step) GONE
int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (currentStep == i) {
child.setVisibility(View.VISIBLE);
} else {
child.setVisibility(View.GONE);
}
}
}
}
public void nextStep() {
int count = getChildCount();
getChildAt(currentStep).setVisibility(View.GONE);
if (currentStep < (count - 1)) {
currentStep++;
preferences.edit().putInt(KEY_LAST_STEP_PASSED, currentStep).commit();
getChildAt(currentStep).setVisibility(View.VISIBLE);
} else {
finishWizard();
}
}
public void previousStep() {
if (currentStep > 0) {
getChildAt(currentStep).setVisibility(View.GONE);
currentStep--;
preferences.edit().putInt(KEY_LAST_STEP_PASSED, currentStep).commit();
getChildAt(currentStep).setVisibility(View.VISIBLE);
}
}
public void finishWizard() {
isWizardFinished = true;
preferences.edit().putBoolean(KEY_WIZARD_FINISHED, true).commit();
setVisibility(View.GONE);
}
}
WizardStep Class:
public class WizardStepView extends RelativeLayout {
public WizardStepView(Context context) {
super(context);
}
public WizardStepView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WizardStepView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}
Sample layout file with Wizard:
<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" >
<com.example.wizardtest.WizardView
android:id="#+id/wizard"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.wizardtest.WizardStepView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:onClick="wizardNext"
android:text="Next(2)" />
</com.example.wizardtest.WizardStepView>
<com.example.wizardtest.WizardStepView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:onClick="wizardNext"
android:text="Next(3)" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:onClick="wizardPrevious"
android:text="Previous(1)" />
</com.example.wizardtest.WizardStepView>
<com.example.wizardtest.WizardStepView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:onClick="wizardPrevious"
android:text="Previous(2)" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:onClick="wizardNext"
android:text="Finish" />
</com.example.wizardtest.WizardStepView>
</com.example.wizardtest.WizardView>
</RelativeLayout>
Activity:
WizardView wizardView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wizardView = (WizardView) findViewById(R.id.wizard);
wizardView.startWizard();
}
i get ClassCastException: android.widget.LinearLayout
i'm trying to catch the fact that view (Lineralayout) has the elements of listview (one of it's children) in it.
customview:
public class MasterView extends View {
public boolean done=false;
public MasterView(Context context) {
super(context);
}
public MasterView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MasterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onFinishInflate() {
// TODO Auto-generated method stub
done=true;
super.onFinishInflate();
}
}
the way I call it:
View master = (View)findViewById(R.id.master);
MasterView master2 = (MasterView)master; //exception
the xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/master"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/cnt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.03" >
</RelativeLayout>
</LinearLayout>
I inflate cnt with the list
The R.id.master element in your xml is not of type MasterView. Change your xml to something like:
<yourpackage.MasterView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/master"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/cnt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.03" >
</RelativeLayout>
</yourpackage.MasterView>