I need to create Collapse / Expand forms in Android. I am thinking about using either RelativeLayout or TableLayout for this purpose. But, what XML element make these forms expand and hide in android?
If you are not sure what I am not talking about, take an application like Sales Force for an example. There you have these expandable menus in all the forms. How can I do this?
Following is an example (taken from Sales Force)
When you expand these, it looks like below
You could do the following. create a layout that has the following:
1. A Heading or a textview with the label contacts
2. Below it a layout that has forms related to it
3. Add another textview below #2 and name it address
4. Add a lyout below #3 .
The layout 2 and 4 will have visibility gone in the first case
When the user taps on layout 1, or the first textview, make layout 2 visible and vice versa. Do the same with the second textview.
Hope that helps.!
I have had a similar problem, i want parts of my form to be hidden in sektions and created a class for this issue.
public class section extends LinearLayout{
public LinearLayout container;
public Button toggler;
public section(Context context, String section_name, String section_state) {
super(context);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.flxsection, this);
container = (LinearLayout) this.findViewById(R.id.container);
container.setVisibility(section_state.equals("0") ? View.GONE:View.VISIBLE);
toggler = ((Button)this.findViewById(R.id.section_toggle));
toggler.setTag(section_state);
toggler.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
String tag = (String) v.getTag();
v.setTag(tag.equals("0") ? "1":"0");
if(tag.equals("0")){expand(container,false);}else{collapse(container,false);}
setImage(tag.equals("0"));
}
});
toggler.setText(" " + section_name);
setImage(section_state.equals("1"));
setTextSize();
}
public void setTextSize(){
toggler.setTextSize(GV.Style.TextSize);
}
public void setImage(boolean open){
int a = open ? R.drawable.minus_48_white: R.drawable.plus_48_white;
Drawable img = main.res.getDrawable(a);
final float scale = main.res.getDisplayMetrics().density;
int size = (int) (12 * scale + 0.5f);
img.setBounds(0,0,size,size);
toggler.setCompoundDrawables(img,null,null,null);
}
}
the xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:focusable="false"
android:layout_marginLeft="4dip"
android:layout_marginRight="4dip"
android:orientation="vertical" >
<Button
android:id="#+id/section_toggle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dip"
android:layout_marginTop="4dip"
android:background="#drawable/section"
android:drawableLeft="#drawable/plus_48"
android:focusable="false"
android:gravity="left|center_vertical"
android:padding="6dip"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:textSize="22dip" />
<LinearLayout
android:id="#+id/container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:background="#android:color/transparent"
android:orientation="vertical" >
</LinearLayout>
Expand and collapse:
public static void expand(final View v,boolean quick) {
v.requestLayout();
v.measure(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
final int targtetHeight = v.getMeasuredHeight();
v.getLayoutParams().height = 0;
v.getLayoutParams().width = LayoutParams.FILL_PARENT;
v.setVisibility(View.VISIBLE);
if(quick){
v.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
v.requestLayout();
}else{
android.view.animation.Animation a = new android.view.animation.Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targtetHeight * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
int duration = (int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density);
if(duration> 500)duration=500;
a.setDuration(duration);
//(int)(targtetHeight / v.getContext().getResources().getDisplayMetrics().density)
v.startAnimation(a);
}
}
public static void collapse(final View v,boolean quick) {
v.requestLayout();
final int initialHeight = v.getMeasuredHeight();
if(quick){
v.setVisibility(View.GONE);
v.requestLayout();
}else{
android.view.animation.Animation a = new android.view.animation.Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if(interpolatedTime == 1){
v.setVisibility(View.GONE);
}else{
v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
v.requestLayout();
}
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
int duration = (int)( initialHeight/ v.getContext().getResources().getDisplayMetrics().density);
if(duration> 500)duration=500;
a.setDuration(duration);
v.startAnimation(a);
}
}
If if create a form and need a section, i create a instance of this class and add the controls.
You might need to turn the hardware acceleration on in order to get the best performance
edit:
Usage is like:
section s = new section(context, section_name, section_state);
s.container.addView([your view 1]);
s.container.addView([your view 2]);
s.container.addView([your view 3]);
//...
form.addView(s);
Related
so I am working on an app, using Android Studio, and I want to basically have 3 layouts. The first being a static background linear layout, that will only have a picture that is the background. Above that, is another Linear layout, that will have "nothing", and above that is an invisible grid layout, that each "box" has two numbers, rows, and columns, and Using that, I will know where to put stuff in my second Linear layout(E.g, If i want to move something to the top right, I will just put in the position 0,0 and it will put it on that position, but on the linear layout, rather than the grid layout.)
I already made the gridlayout, and the linear layouts, here is the xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/map_backround"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/grassGreen"
android:gravity="center"
android:visibility="visible">
<ImageView
android:id="#+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible"
app:srcCompat="#drawable/greenBackround" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/mapPosition">
<GridLayout
android:id="#+id/map_hardcore"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="4dp"
android:gravity="center"
android:horizontalSpacing="0dp"
android:numColumns="270"
android:stretchMode="columnWidth"
android:verticalSpacing="0dp"
android:visibility="invisible">
</GridLayout>
</LinearLayout>
</LinearLayout>
And The baseAdapter. Take in mind, class Map is basically a Class that inherits Coordination, and has a 2d array of coordinates (creating a 2d map of coordinates), And coordinates is just a class with 2 integers, one for rows and one for columns, giving me an id for each square.
public class gridViewHandler extends BaseAdapter
{
Context context;
private Map selectedMap;
private Coordination[][] position;
private int countLocations;
public gridViewHandler(Context context, Map selectedMap)
{
this.countLocations = 0;
this.context = context;
this.selectedMap = selectedMap;
this.position = selectedMap.getMapParams();
for(int i = 0; i < selectedMap.getColumns(); i++)
{
for(int a = 0; a < selectedMap.getRows(); a++)
{
countLocations++;
}
}
}
#Override
public int getCount()
{
return countLocations;
}
public int getColumnCount()
{
return position.length;
}
public int getRowCount()
{
return position[0].length;
}
public Object getItem(int colNum, int rowNum)
{
return position[colNum][rowNum];
}
#Override
public Object getItem(int i)
{
return null;
}
#Override
public long getItemId(int i)
{
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
return null;
}
}
Lastly, Here is what my "Main_Activity" looks like(I called it game)
public class Game extends Activity {
private GridView defaultMap;
private Map map = new Map();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
defaultMap = (GridView) this.findViewById(R.id.map_hardcore);
gridViewHandler gridAdapter = new gridViewHandler(Game.this, map);
defaultMap.setAdapter(gridAdapter);
}
}
So, I don't really know how I can use what I already made. I think that the gridview is ready, and all I need to do is create the two linear layouts, then create the function where I insert the ID of the gridview box(rows,cols) and an item, and it will display it on the linear layout in that position. Any Idea how I can implement this?
My goal to achieve is a map where I will always be able to know, and control where every object is.
I am brand new to Android Studio and am trying to figure out how to change the background color of my start up app.
The moment the app loads, I see a button on the screen, and when I click, it goes to the color red.
What I want is when you click the button, it goes from red to green to blue than back to red.
However, I keep getting these errors:
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
Compilation failed; see the compiler error output for details.
Error:(72, 9) error: class, interface, or enum expected
Main Activity XML File:
<?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="match_parent"
android:orientation="vertical"
android:id="#+id/layout">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change Color"
android:onClick="onChangeColor"/>
</LinearLayout>
Test Activity Java Code:
private int colorIndex = 1;
public void onChangeColor(View view) {
int color;
if(colorIndex==0) {
color = Color.RED;
colorIndex = 1;
}else if(colorIndex==1) {
color = Color.GREEN;
colorIndex = 2;
}else {
//colorIndex = 2
color = Color.BLUE;
colorIndex = 0;
}
View layout = findViewById(R.id.layout);
layout.setBackgroundColor(color);
}
public class TestActivity extends AppCompatActivity {
View view;
//declare a string variable in java a class
//private var colour = "green";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View layout = findViewById(R.id.layout);
layout.setBackgroundColor(Color.RED);
view= this.getWindow().getDecorView();
view.setBackgroundResource(R.color.gray);
}
public void goRed(View v)
{
//if (colour == "green"){
view.setBackgroundResource(R.color.red);
//colour = "red";
//}
}
}
To give you a excellent help, it will be necessary to see you code.
Any way if i andersted you right maybe this will help you :
On your xml layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/layout">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change Color"
android:onClick="onChangeColor"/>
</LinearLayout>
On your activity :
private int colorIndex = 1;
public void onChangeColor(View view) {
int color;
if(colorIndex==0) {
color = Color.RED;
colorIndex = 1;
}else if(colorIndex==1) {
color = Color.GREEN;
colorIndex = 2;
}else {
//colorIndex = 2
color = Color.BLUE;
colorIndex = 0;
}
View layout = findViewById(R.id.layout);
layout.setBackgroundColor(color);
}
On you onCreate in the activity
View layout = findViewById(R.id.layout);
layout.setBackgroundColor(Color.RED);
If I understood correctly what you want is, to transition over a series of colours over time, and each colour lasting for some 1-2 seconds. You can use Android's default CountDownTimer.
Keep Your xml layout same.
In your Activity:
public class TestActivity extends AppCompatActivity {
LinearLayout layout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (LinearLayout)findViewById(R.id.layout);
layout.setBackgroundColor(Color.RED);
}
public void onChangeColor(View view) {
// start your timer on button click
new CountDownTimer(3000, 1000) {
public void onTick(long millisUntilFinished) {
changeBackground(3-millisUntilFinished/1000);
}
}.start();
}
private void changeBackground(int colorIndex){
int color;
if(colorIndex==1) {
color = Color.GREEN;
}else if(colorIndex==2) {
color = Color.BLUE;
}else {
color = Color.RED;
}
layout.setBackgroundColor(color);
}
}
Hope this might help. If I misunderstood something please comment.
Edit: I typecasted View to LinearLayout
Since i could not find anything related in the internet, this is gonna be my first SO question:
Problem Description
I am experiencing the following issue:
In my app i have a RecyclerView with a GridLayoutManager which is displaying images loaded by Glide.
When scrolling slowly everything will work alright.
After scrolling fast up and down (to an extend one could arguably call it "abuse of scrolling") some image parts or whole images will randomly overlay my screen, so that the content below is no longer visible. This is especially the case on the edges of the screen.
The testing device where the described error occurs is a OnePlus One running CM12.1.1 (Android 5.1.1). I didn't test on other devices.
Any hints / help / explanation on why this is happening or how to fix it are appreciated.
CODE
Below is the code for the Adapter with an inner ViewHolder class:
public class PhotoListAdapter extends RecyclerView.Adapter<PhotoListAdapter.PhotoHolder>{
private ArrayList<PhotoDetail> mPhotos;
private String mAccessToken;
private int mUserId;
private int mPageCounter = 1;
private boolean mIsLoading = false;
private boolean mEndReached = false;
public PhotoListAdapter (String accessToken, int userId){
mPhotos = new ArrayList<>();
mAccessToken = accessToken;
mUserId = userId;
fetchPhotos();
}
#Override
public PhotoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_photo_list_item, parent, false);
PhotoHolder photoHolder = new PhotoHolder(itemView);
return photoHolder;
}
#Override
public void onBindViewHolder(PhotoHolder holder, int position) {
holder.bind(mPhotos.get(position));
if (position == mPhotos.size() - 6) fetchPhotos();
}
#Override
public int getItemCount() {
return mPhotos.size();
}
public void fetchPhotos () {
if (mIsLoading || mEndReached) return;
else {
mIsLoading = true;
//Retrofit call which will return a JSON Object with the Photo Details, like the filename
// With this information i can build the URL of the image
ApiProvider.getInstance().getApi().getPhotos(mUserId, mAccessToken, "time", "all", mPageCounter, mUserId, 32).enqueue(new Callback<PhotoResponseWrapper>() {
#Override
public void onResponse(Call<PhotoResponseWrapper> call, Response<PhotoResponseWrapper> response) {
if (response.code() == HttpURLConnection.HTTP_OK){
int photoCount = response.body().getPhotoResponse().getPhotosCount();
if (photoCount != 32) mEndReached = true;
Collections.addAll(mPhotos, response.body().getPhotoResponse().getPhotos());
notifyItemRangeInserted(mPhotos.size() - photoCount,photoCount);
mPageCounter++;
}
mIsLoading = false;
}
#Override
public void onFailure(Call<PhotoResponseWrapper> call, Throwable t) {
mIsLoading = false;
}
});
}
}
class PhotoHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ImageView mPhotoView;
private PhotoDetail mPhotoDetail;
public PhotoHolder(View itemView) {
super(itemView);
mPhotoView = (ImageView) itemView.findViewById(R.id.img_photo);
mPhotoView.setOnClickListener(this);
}
public void bind (PhotoDetail photoDetail){
mPhotoDetail = photoDetail;
String photoUrl = Api.Endpoints.PHOTOS_SMALL + photoDetail.getUserId() + '/' + photoDetail.getFileName();
mPhotoView.setContentDescription(photoDetail.getDescription());
// First stop all pending image loads
Glide.clear(mPhotoView);
// Then load new url
Glide.with(mPhotoView.getContext())
.load(photoUrl)
.into(mPhotoView);
}
#Override
public void onClick(View v) {
}
}
}
Below is the XML of a single Item:
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/img_photo"
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="#dimen/height_photo_item"
android:padding="#dimen/padding_photo_item"
android:scaleType="centerCrop"/>
Below is the XML of the RecyclerView:
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout_swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingRight="#dimen/padding_photo_item"
android:paddingLeft="#dimen/padding_photo_item"
android:paddingTop="#dimen/padding_photo_item"
tools:context=".fragments.PhotoListFragment">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
EXAMPLES
Some visual examples of the bug are these screenshots:
You have to use placeholder image.
Glide.with(mPhotoView.getContext())
.load(photoUrl)
.placeholder(R.drawable.image_placeholder) // Your placeholder image
.into(mPhotoView);
I had the same problem and setting the placeholder eliminated it for me.
Since I couldn't find any information on how to fix this, i tried out the major alternative image loading & caching library - Picasso.
With this library the bug mentioned above wasn't reproducible for me, so i guess it is really Glide specific.
Imagine a number 10, then after user clicks a button it changes to 100. But how to make an efficient transition
10 -> 100,
that will display values like
12, 15, 18, ..., 97, 100 over 1 second.
I've seen something like that in "Cookie clicker" but couldn't find anything about that kind of transition in the source code.
I had an idea of a loop (for number1 < number2, do number1++), it will work fine for small numbers, but if 10 changes to 1 billion, then the loop will probably freeze the whole app.
Second idea is to get added value (100-10=90) and divide by 30 or 60 frames, and add this value with each frame. But what will happen if frame is dropped? - Probably value will not be added. What if user makes double click or the system adds values automatically?
Hope it gives an idea of what kind of number transition I need.
Maybe I overlooked and there is a simple approach? Any help is appreciated.
Hope this little demo using a ValueAnimator will inspire you to find an appropriate solution.
You can specify the duration of the animation (see code) and even adjust the frame-rate by saying mAnimator.setFrameDelay(frameDelay);.
By using animator.isRunning() or animator.isStarted() you can prevent double-click malfunction or other unwanted behaviour while the current animation is runnning.
The Main Activity:
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
tv.setText(String.format("%04d", value));
}
});
mAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animator) {
super.onAnimationEnd(animator);
final int endValue = Integer.parseInt((String) tv.getText());
mAnimator.setIntValues(endValue, endValue + 100);
}
});
}
/** Button callback */
public void onClick(final View view) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
mAnimator.start();
}
}
}
Simple demo layout:
<LinearLayout 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"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100"
android:onClick="onClick">
</Button>
Here's another demo (hope this answers your 2. question), which implements different behaviour dependent on single click or double-click on the button. Just experiment with it, you now have the basic building blocks to construct own behavour ...
/** ValueAnimator demo */
public class MainActivity extends Activity {
ValueAnimator mAnimator;
TextView mTv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTv = (TextView) findViewById(R.id.textview);
mAnimator = ValueAnimator.ofInt(1, 100).setDuration(1000);
mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mAnimator.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
final Integer value = (Integer) animator.getAnimatedValue();
mTv.setText(String.format("%04d", value));
}
});
final Button button = (Button) findViewById(R.id.button);
final GestureDetector gestureDetector = new GestureDetector(this,
new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDoubleTap(MotionEvent e) {
performAnimation(100);
return true;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
performAnimation(0);
return true;
}
});
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
}
/** starts animation */
private void performAnimation(final int offset) {
if (!mAnimator.isStarted() && !mAnimator.isRunning()) {
final int endValue = Integer.parseInt((String) mTv.getText());
mAnimator.setIntValues(endValue + offset, endValue + 100 + offset);
mAnimator.start();
}
}
}
Don't forget to replace your layout file, since the click-attribute of the button has been removed:
<LinearLayout 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"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:typeface="monospace"
android:text="0001" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Gimme +100" >
</Button>
</LinearLayout>
I guess you can do it by using different threads. Only main thread works with UI so you can divide the interval into small intervals and make a transitions in different threads.After send them to main thread and print. Hope it will help.
I'm fairly new to android dev and am trying to learn ropes. In order to do that I've been messing around Custom Views in android. I am trying to build an alarm clock app and I want to make a nice spinner to select the times from. Similar to say this:
http://i47.tinypic.com/aymyjc.jpg
I have created an AndroidScollSpinner class that looks like this:
public class AndroidScrollSpinner extends View {
public AndroidScrollSpinner(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBackground(canvas);
drawSomeText(canvas);
canvas.restore();
}
private void drawSomeText(Canvas canvas) {
Paint titlePaint = new Paint();
titlePaint.setColor(Color.BLUE);
canvas.drawTextOnPath("Bert", new Path(), 0.0f,0.0f, titlePaint);
}
private void drawBackground(Canvas canvas) {
Paint backgroundPaint = new Paint();
backgroundPaint.setColor(getResources().getColor(R.color.bluegrass));
backgroundPaint.setStyle(Paint.Style.FILL);
Bitmap background = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
canvas.drawBitmap(background, 0, 0, backgroundPaint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
int w = Math.max(minw, MeasureSpec.getSize(widthMeasureSpec));
int h = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(w, h);
}
}
The issue I am having is in the onMeasure
The MeasureSpec.getSize(widthMeasureSpec) always returns 0. Does anyone know why? Or what I am missing here?
Here's my layout file as well.
<?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="wrap_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:id="#+id/addAlarmSpinnerLayout">
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content">
<ToggleButton android:id="#+id/sundayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/S"
android:textOff="#string/S"/>
<ToggleButton android:id="#+id/mondayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/M"
android:textOff="#string/M"/>
<ToggleButton android:id="#+id/tuesdayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/T"
android:textOff="#string/T"/>
<ToggleButton android:id="#+id/wednesdayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/W"
android:textOff="#string/W"/>
<ToggleButton android:id="#+id/thursdayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/T"
android:textOff="#string/T"/>
<ToggleButton android:id="#+id/fridayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/F"
android:textOff="#string/F"/>
<ToggleButton android:id="#+id/saturdayToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.14"
android:textOn="#string/S"
android:textOff="#string/S"/>
</LinearLayout>
<Button android:id="#+id/doneButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/done"
android:onClick="onDoneClicked">
</Button>
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hour24Clock"
android:id="#+id/hour24switch"
android:layout_gravity="center"
android:enabled="true"
android:onClick="createSpinners"/>
</LinearLayout>
If you need to know anything else about the app, have a look here under https://github.com/rdsmallwood928/NeverLate
Also I do realize that there probably third party libraries out there that I can use to get the spinner effect that I want. However, I'm really doing this as a learning exercise so it more important to me to understand why this code always returns 0 than to inject a custom component from somewhere else and get on with my life. Thanks in advance for your help!
EDIT: Here is the AddAlarmFragment class that creates the spinners
public class AddAlarmFragment extends Fragment {
private AndroidClickSpinner minuteSpinner;
private AndroidClickSpinner hourSpinner;
private AndroidClickSpinner amPmSpinner;
private ToggleButton mondayToggle;
private ToggleButton tuesdayToggle;
private ToggleButton wednesdayToggle;
private ToggleButton thursdayToggle;
private ToggleButton fridayToggle;
private ToggleButton saturdayToggle;
private ToggleButton sundayToggle;
private Switch hour24Switch = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.add_alarm, container, false);
}
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
createSpinners(view);
}
#Override
public void onResume() {
super.onResume();
}
public void createSpinners(View view) {
LinearLayout layout = (LinearLayout) view.findViewById(R.id.addAlarmSpinnerLayout);
hour24Switch = (Switch) view.findViewById(R.id.hour24switch);
layout.removeAllViews();
ArrayList<Object> hours = new ArrayList<>();
if(hour24Switch.isChecked()) {
for(int i=0;i<24;i++) hours.add(i);
} else {
for(int i=1;i<=12;i++) hours.add(i);
}
hourSpinner = new AndroidClickSpinner(getActivity(), hours);
layout.addView(hourSpinner);
ArrayList<Object> minutes = new ArrayList<>();
for(int i=0;i<=60;i++) minutes.add(i);
minuteSpinner = new AndroidClickSpinner(getActivity(), minutes);
layout.addView(minuteSpinner);
if(!hour24Switch.isChecked()) {
ArrayList<Object> amPm = new ArrayList<>();
amPm.add("AM");
amPm.add("PM");
amPmSpinner = new AndroidClickSpinner(getActivity(), amPm);
layout.addView(amPmSpinner);
}
mondayToggle = (ToggleButton) view.findViewById(R.id.mondayToggleButton);
tuesdayToggle = (ToggleButton) view.findViewById(R.id.tuesdayToggleButton);
wednesdayToggle = (ToggleButton) view.findViewById(R.id.wednesdayToggleButton);
thursdayToggle = (ToggleButton) view.findViewById(R.id.thursdayToggleButton);
fridayToggle = (ToggleButton) view.findViewById(R.id.fridayToggleButton);
saturdayToggle = (ToggleButton) view.findViewById(R.id.saturdayToggleButton);
sundayToggle = (ToggleButton) view.findViewById(R.id.sundayToggleButton);
//Prevent no day selected...
switch (new LocalDate().getDayOfWeek()) {
case 1:
mondayToggle.setSelected(true);
break;
case 2:
tuesdayToggle.setSelected(true);
break;
case 3:
wednesdayToggle.setSelected(true);
break;
case 4:
thursdayToggle.setSelected(true);
break;
case 5:
fridayToggle.setSelected(true);
break;
case 6:
saturdayToggle.setSelected(true);
break;
case 7:
sundayToggle.setSelected(true);
break;
}
PieChart pie = new PieChart(getActivity());
Resources res = getResources();
pie.addItem("Agamemnon", 2, res.getColor(R.color.seafoam));
pie.addItem("Bocephus", 3.5f, res.getColor(R.color.chartreuse));
pie.addItem("Calliope", 2.5f, res.getColor(R.color.emerald));
pie.addItem("Daedalus", 3, res.getColor(R.color.bluegrass));
pie.addItem("Euripides", 1, res.getColor(R.color.turquoise));
pie.addItem("Ganymede", 3, res.getColor(R.color.slate));
layout.addView(pie);
layout.addView(new AndroidScrollSpinner(getActivity()));
}
public Integer getHours() {
Integer hour = Integer.parseInt(hourSpinner.getSelectedItem().toString());
if(!hour24Switch.isChecked()) {
if(hour == 12) {
hour = 0;
}
if(amPmSpinner.getSelectedItem().equals("PM")) {
hour = hour + 12;
}
}
return hour;
}
public Integer getMinutes() {
return Integer.parseInt(minuteSpinner.getSelectedItem().toString());
}
public boolean[] getDays() {
boolean[] days = new boolean[7];
days[0] = mondayToggle.isChecked();
days[1] = tuesdayToggle.isChecked();
days[2] = wednesdayToggle.isChecked();
days[3] = thursdayToggle.isChecked();
days[4] = fridayToggle.isChecked();
days[5] = saturdayToggle.isChecked();
days[6] = sundayToggle.isChecked();
return days;
}
}
I'm sorry, but where in your layout you are using it ?
Are you adding it from code, since I couldn't see it included somewhere in your XML layout file