Why is my custom spinner disabled/unresponsive? - java

I've created a custom spinner, because again and again, I found that I wanted to make sure that the onItemSelectedListener wasn't triggered when I set my Spinner's initial selection or set a new custom adapter. I only want it triggered when a user actually selects an item.
But for some reason (I'm at a complete loss as to why), my custom spinner doesn't respond to touch events. It's as if it's disabled, even though I've debugged and seen that it's perfectly enabled. But for some reason, my little spinner won't open. Can anyone help me understand why?
Here's the xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="#dimen/default_margin"
android:orientation="horizontal">
<my.app.custom.view.MySpinner
android:id="#+id/dog_or_cat_toggle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:layout_margin="0dp"
android:textAlignment="center"
android:gravity="center_vertical|center"
android:padding="0dp"
android:entries="#array/dog_or_cat"
android:spinnerMode="dropdown"
android:background="#drawable/top_to_bottom_gray_gradient"/>
...
</LinearLayout>
And my Custom Spinner:
/* A Spinner dispatches an onItemSelected event when the View is initialized, before the user ever makes a selection.
* This class allows listeners for just the initial selection, just user selections, or both. */
public class MySpinner extends Spinner {
private boolean initialized = false;
private OnItemSelectedListener onItemSelectionInitializedListener;
private OnItemSelectedListener onItemSelectedByUserListener;
private OnItemSelectedListener onItemSelectedListener;
public MySpinner(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MySpinner(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public MySpinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
this.initializeMySpinner();
}
public void setOnItemSelectionInitializedListener(OnItemSelectedListener onItemSelectionInitializedListener) {
this.onItemSelectionInitializedListener = onItemSelectionInitializedListener;
}
public void setOnItemSelectedByUserListener(OnItemSelectedListener onItemSelectedByUserListener) {
this.onItemSelectedByUserListener = onItemSelectedByUserListener;
}
#Override
public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
this.onItemSelectedListener = onItemSelectedListener;
}
#Override
public void setAdapter(SpinnerAdapter adapter) {
this.initialized = false;
super.setAdapter(adapter);
}
private void initializeMySpinner() {
super.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if(!initialized) {
if(onItemSelectionInitializedListener != null) onItemSelectionInitializedListener.onItemSelected(parent, view, position, id);
if(onItemSelectedListener != null) onItemSelectedListener.onItemSelected(parent, view, position, id);
initialized = true;
} else {
if(onItemSelectedListener != null) onItemSelectedListener.onItemSelected(parent, view, position, id);
if(onItemSelectedByUserListener != null) onItemSelectedByUserListener.onItemSelected(parent, view, position, id);
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
if(!initialized) {
if(onItemSelectionInitializedListener != null) onItemSelectionInitializedListener.onNothingSelected(parent);
if(onItemSelectedListener != null) onItemSelectedListener.onNothingSelected(parent);
initialized = true;
} else {
if(onItemSelectedListener != null) onItemSelectedListener.onNothingSelected(parent);
if(onItemSelectedByUserListener != null) onItemSelectedByUserListener.onNothingSelected(parent);
}
}
});
}
}

Don't call one constructor from another. Instead, call super() constructor from each one.
I have faced the same issue some time back and this trick worked, but I'm not sure about the reason.

Related

Android RecyclerView fails to render a SurfaceView (SOLVED)

can a SurfaceView be rendered inside a RecyclerView
what i am trying to do is make a Grid of SurfaceView's
#Keep
public class NativeView {
String TAG = "EglSample";
public static native void nativeOnStart();
public static native void nativeOnResume();
public static native void nativeOnPause();
public static native void nativeOnStop();
// this is part of graphics manager
public native void nativeSetSurface(Surface surface);
View surfaceView = null;
SurfaceHolderCallback surfaceHolderCallback = null;
public NativeView(Context context) {
System.loadLibrary("nativeegl");
surfaceHolderCallback = new SurfaceHolderCallback();
surfaceView = new View(surfaceHolderCallback, context);
}
class View extends SurfaceView {
public View(SurfaceHolder.Callback callback, Context context) {
super(context);
getHolder().addCallback(callback);
}
public View(SurfaceHolder.Callback callback, Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(callback);
}
public View(SurfaceHolder.Callback callback, Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
getHolder().addCallback(callback);
}
public View(SurfaceHolder.Callback callback, Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
super(context, attrs, defStyle, defStyleRes);
getHolder().addCallback(callback);
}
}
class SurfaceHolderCallback implements SurfaceHolder.Callback {
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
nativeSetSurface(holder.getSurface());
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
nativeSetSurface(null);
}
}
}
public ViewGroup onViewRequest(Context mContext) {
if (context == null) context = mContext;
if (n == null) n = new NativeView(context);
Log.i(n.TAG, "onViewRequest(Activity, Context)");
// build layout
RelativeLayout rel = new RelativeLayout(context);
rel.addView(n.surfaceView);
n.surfaceView.setOnClickListener(new MyListener());
// set text
TextView text = new TextView(context);
text.setText("Hello World! Try clicking the screen");
text.setTextSize(60f);
text.setTextColor(Color.WHITE);
rel.addView(text);
Log.i(n.TAG, "onCreate()");
// build layout
NativeView.nativeOnStart();
NativeView.nativeOnResume();
return rel;
}
full:
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/vstdemoopengladdonscube/src/main/java/vst/demo/opengl/addons/cube/main.java
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/vstdemoopengladdonscube/src/main/java/vst/demo/opengl/addons/cube/NativeView.java
as it renders corrupted in a recycler view (text but no surface view) (you can barely make out the white text but the fact that it is there means the view heirarchy IS being drawn)
(set USE_RECYCLER_VIEW = true)
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/VstManager/src/main/java/vst/manager/VstGrid.java#L29
Boolean USE_RECYCLER_VIEW = false;
public LinearLayout getView() {
// this assumes the first available "*\.addons\.*" package
if (!USE_RECYCLER_VIEW) {
VST pkg = mVstMan.loadPackage(mActivity, mVstMan.getPackages(mActivity)[0].packageName, false);
VST.CLASS vstClass = mVstMan.loadClass(pkg, "main");
Object vstClassInstance = mVstMan.newInstance(vstClass, "main");
// android.widget.RelativeLayout cannot be cast to android.widget.LinearLayout
LinearLayout x = new LinearLayout(mActivity);
x.addView((ViewGroup) mVstMan.invokeMethod(
vstClass, vstClassInstance,
"onViewRequest", Context.class,
pkg.activityApplicationContext
)
);
return x;
} else {
if (recyclerViewMain == null)
recyclerViewMain = (LinearLayout) LayoutInflater.from(mActivity.getApplicationContext())
.inflate(R.layout.vst_grid, null, false);
if (recyclerView == null) {
recyclerView = recyclerViewMain
.findViewById(R.id.VstGrid);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true);
}
if (layoutManager == null) {
// use a linear layout manager
layoutManager = new GridLayoutManager(mActivity, 1);
recyclerView.setLayoutManager(layoutManager);
}
if (mAdapter == null) {
// specify an adapter (see also next example)
mAdapter = new VstGridAdapter(mActivity, mVstMan, mVstUI);
recyclerView.setAdapter(mAdapter);
}
mAdapter.update();
return recyclerViewMain;
}
}
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/VstManager/src/main/java/vst/manager/VstGridAdapter.java#L86
// Create new views (invoked by the layout manager)
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
VST pkg = mVstMan.loadPackage(mActivity, mVstMan.getPackages(mActivity)[0].packageName, false);
VST.CLASS vstClass = mVstMan.loadClass(pkg, "main");
Object vstClassInstance = mVstMan.newInstance(vstClass, "main");
// android.widget.RelativeLayout cannot be cast to android.widget.LinearLayout
LinearLayout x = new LinearLayout(mActivity);
x.addView((ViewGroup) mVstMan.invokeMethod(
vstClass, vstClassInstance,
"onViewRequest", Context.class,
pkg.activityApplicationContext
)
);
return new MyViewHolder(x);
}
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/vstdemoopengladdonscube/src/main/cpp/RotatingSquares/jniapi.cpp
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/vstdemoopengladdonscube/src/main/cpp/RotatingSquares/renderer.cpp#L153
meanwhile it renders perfectly fine if NOT in a recycler view (leave USE_RECYCLER_VIEW as false)
why?
apparently in order to get it to display i needed to give the view fixed size layout paramaters: mView.setLayoutParams(new ViewGroup.LayoutParams(500, 500));

Reopening Activity from Spinner in Android [duplicate]

I want to fire a event when the same item is selected in spinner. Method
#Override
public void onItemSelected(AdapterView<?> parent, View arg1, int position,
long arg3) {
}
is called only when we different selection is made. My Purpose is to display a toast when any item is selected either the same item is reselected or different selection is made.
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
above method does not solve my problem.
i have found that old selection is kept at variable called mOldSelectedPosition in the hierarcy of the spinner. Spinner is using this value to check if the same item selected or not , and if it is the same , it ignores. If we dont wanna ignore this What i did is some dirty code using reflection.
package com.aradiom.amc.nativecomponents;
import java.lang.reflect.Field;
import android.content.Context;
import android.util.Log;
import android.widget.Spinner;
public class SpinnerTrigger extends Spinner {
public SpinnerTrigger(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
public void setSelection(int position, boolean animate) {
ignoreOldSelectionByReflection();
super.setSelection(position, animate);
}
private void ignoreOldSelectionByReflection() {
try {
Class<?> c = this.getClass().getSuperclass().getSuperclass().getSuperclass();
Field reqField = c.getDeclaredField("mOldSelectedPosition");
reqField.setAccessible(true);
reqField.setInt(this, -1);
} catch (Exception e) {
Log.d("Exception Private", "ex", e);
// TODO: handle exception
}
}
#Override
public void setSelection(int position) {
ignoreOldSelectionByReflection();
super.setSelection(position);
}
}
This class will always invalidate the oldselection value , so that every time on click event gets triggered.
It may not be perfect solution. Use with caution. :)
Hopefully this help. I tried and it works
/** Spinner extension that calls onItemSelected even when the selection is the same as its previous value */
public class NDSpinner extends Spinner {
public NDSpinner(Context context)
{ super(context); }
public NDSpinner(Context context, AttributeSet attrs)
{ super(context, attrs); }
public NDSpinner(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
#Override public void
setSelection(int position, boolean animate)
{
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position, animate);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
#Override public void
setSelection(int position)
{
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}
Since my reputation is not high enough to comment directly on #Suat 's answer, I tried that method, it works like charm, but I'm not clear what the side effects could be.
Something I want to add is, additional constructors should be added to avoid errors.
public SpinnerTrigger(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
public SpinnerTrigger(Context context, AttributeSet attrs){
super(context,attrs);
}
You can add a method name on your item selected METHOD
Spinner `Spinner1`=(Spinner)findViewById(R.id.`declareid`)
oBject has been declared for spinner
#Override
public void onItemSelected(AdapterView<?> parent, View arg1, int position,
long arg3)
{
ItemOnChange();
}
private void ItemOnChange() {
if(Spinner1.getSelectedItemPosition()>0){
pd=ProgressDialog.show(this,"","Loading, Please wait .. ",true);
final int spinner=Spinner1.getSelectedItemPosition();
final Handler ThreadCallback=new Handler();
final Runnable runInCityThread=new Runnable(){
public void run(){
fnBindspimmer2();
pd.dismiss();
}
};
new Thread(){
#Override public void run(){
Spinner2values();
ThreadCallback.post(runInCityThread);
}
}.start();
}
}
use click listener to fulfill your requirement. as direct click listener on spinner doesn't supported so make a class extend spinner and over ride on click method and in this method do what you want to do.

GridView row not inflating

I have a simple GridView with custom Adapter in my layouts. My code is as follows:
CircleActivity.java:
public class CircleActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circle);
List<Integer> listColors = new ArrayList<>();
listColors.add(getResources().getColor(R.color.colorAccent));
listColors.add(getResources().getColor(R.color.colorPrimary));
listColors.add(getResources().getColor(R.color.colorPrimaryDark));
GridView gridView = (GridView) findViewById(R.id.grid_colors);
CircleAdapter adapter = new CircleAdapter(this,listColors);
gridView.setAdapter(adapter);
}
}
activity_circle.xml:
<?xml version="1.0" encoding="utf-8"?>
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_colors"
android:layout_width="match_parent"
android:layout_height="match_parent" />
CircleAdapter.java:
public class CircleAdapter extends BaseAdapter{
private Context context;
private List<Integer> listColor;
public CircleAdapter(Context context, List<Integer> listColor) {
this.listColor = listColor;
this.context = context;
}
#Override
public int getCount() {
return listColor.size();
}
#Override
public Integer getItem(int position) {
return listColor.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_grid,parent,false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.customCircleView.setFillColor(listColor.get(position));
holder.customCircleView.setCircleRadius(100);
return convertView;
}
static class ViewHolder{
private CustomCircleView customCircleView;
public ViewHolder(View row){
customCircleView = (CustomCircleView) row.findViewById(R.id.custom_circle_view);
}
}
}
row_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="#color/colorAccent"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="match_parent">
<com.droidexperiments.gridexpand.CustomCircleView
android:id="#+id/custom_circle_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:fill_color="#color/colorPrimary"
custom:circle_radius="50"
android:padding="25dp" />
</LinearLayout>
CircleView.java:
public class CustomCircleView extends View {
private int circleRadius = 20;
private int fillColor = Color.BLACK;
public CustomCircleView(Context context) {
super(context);
}
public CustomCircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CustomCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomCircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(R.styleable.CustomCircle);
circleRadius = typedArray.getInteger(R.styleable.CustomCircle_circle_radius,20);
fillColor = typedArray.getColor(R.styleable.CustomCircle_fill_color, Color.BLACK);
typedArray.recycle();
}
public int getCircleRadius() {
return circleRadius;
}
public void setCircleRadius(int circleRadius) {
this.circleRadius = circleRadius;
}
public int getFillColor() {
return fillColor;
}
public void setFillColor(int fillColor) {
this.fillColor = fillColor;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(fillColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(canvas.getWidth()/2,canvas.getHeight()/2,circleRadius,paint);
}
}
attrts.xml:
<declare-styleable name="CustomCircle">
<attr name="fill_color" format="reference|color"/>
<attr name="circle_radius" format="integer"/>
</declare-styleable>
The issue is that screen remains blank and no row is inflated/showing in GridView.
I have checked everything. There is not any issue in GridView or the layout of grid row or in CustomCircleView. If I change adapter to simple ArrayAdapter, it works fine. So, there must be issue with my adapter:
I double checked getView() in adapter;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_grid,parent,false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.customCircleView.setFillColor(listColor.get(position));
holder.customCircleView.setCircleRadius(100);
return convertView;
}
but couldn't identify why it shows blank. can anyone help me please?
When you implement a custom view, it is essential that you implement onMeasure. This method will tell the Android framework what size your view should be. Since you didn't specify this for CustomCircleView and used wrap_content in your layout, it had size zero. Therefore, all the elements of the GridView were invisible, making it look like the adapter was not working. I made a simple example implementation of onMeasure that solves your problem (just add this method in CustomCircleView):
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = View.MeasureSpec.makeMeasureSpec(2 * this.circleRadius, MeasureSpec.EXACTLY);
setMeasuredDimension(size, size);
}
The documentation advises that size stays within the given parameters (widthMeasureSpec and heightMeasureSpec). I have not included that restriction here, you can determine yourself what you want to do in that case.
You can find more information about this in the guide on creating custom components. Specific information about onMeasure can be found here.

Android Spinner not working on Samsung Devices with Android 5.0

I'm using a custom Spinner widget with the code below.
Everything works fine on most devices except on Samsung's devices with Android 5.0. On click the Spinner should display a list of values but that doesn't happen.
On emulators and others brands devices with Android 5.0 it works fine.
Has anyone faced a similiar isse or have any idea of what might be happening?
xml
<?xml version="1.0" encoding="utf-8"?>
<Spinner
android:id="#+id/_combo_spinner"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:focusable="false"
android:background="#null"
android:clickable="false"
android:paddingBottom="#dimen/cell_text_section_text_padding_bottom"
android:paddingLeft="#dimen/cell_text_section_text_padding_left"
android:paddingRight="#dimen/cell_text_section_text_padding_right"
android:paddingTop="#dimen/cell_text_section_text_padding_top"
android:spinnerMode="dropdown" />
<View
android:layout_width="#dimen/drawable_stroke_width"
android:layout_height="match_parent"
android:layout_marginBottom="5dp"
android:layout_marginTop="3dp"
android:background="#color/stroke_dark_grey"
android:paddingBottom="#dimen/cell_text_section_text_padding_bottom"
android:paddingTop="#dimen/cell_text_section_text_padding_top" />
<ImageView
style="#style/image__default"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center"
android:layout_marginLeft="#dimen/cell_text_section_text_padding_left"
android:layout_marginRight="#dimen/cell_text_section_text_padding_right"
android:src="#drawable/ic_action_expand" />
Java
public class ComboBoxView extends LinearLayout {
private Spinner mSpinner;
private OnItemSelectedListener mListener;
public ComboBoxView(Context context) {
super(context);
initializeLayout(context);
}
public ComboBoxView(Context context, AttributeSet attrs) {
super(context, attrs);
initializeLayout(context);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public ComboBoxView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initializeLayout(context);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ComboBoxView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initializeLayout(context);
}
// Internal methods:
/**
* Initializes the layout
*
* #param context
*/
private void initializeLayout(final Context context) {
mListener = null;
// Inflate and retrieve the views:
this.setOrientation(LinearLayout.VERTICAL);
LayoutInflater.from(context).inflate(R.layout.view_combo_box, this);
mSpinner = (Spinner) findViewById(R.id._combo_spinner);
// Finish initialization:
final int paddingTop = (int) getResources().getDimension(R.dimen.cell_text_section_text_padding_top);
final int paddingBottom = (int) getResources().getDimension(R.dimen.cell_text_section_text_padding_bottom);
final int paddingLeft = (int) getResources().getDimension(R.dimen.cell_text_section_text_padding_left);
final int paddingRight = (int) getResources().getDimension(R.dimen.cell_text_section_text_padding_right);
setOnClickListener(onClick);
setOrientation(LinearLayout.HORIZONTAL);
setBackgroundResource(R.drawable.button_primary);
setClickable(true);
setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
private final OnClickListener onClick = new OnClickListener() {
#Override
public void onClick(View v) {
mSpinner.performClick();
}
};
#Override
public void clearFocus() {
super.clearFocus();
mSpinner.clearFocus();
}
// External methods:
/**
* Interface definition for a callback to be invoked when
* an item in this view has been selected (extracted from {#link AdapterView.OnItemSelectedListener}).
*/
public interface OnItemSelectedListener {
/**
* <p>Callback method to be invoked when an item in this view has been
* selected. This callback is invoked only when the newly selected
* position is different from the previously selected position or if
* there was no selected item.</p>
* <p/>
* Impelmenters can call getItemAtPosition(position) if they need to access the
* data associated with the selected item.
*
* #param parent The ComboBoxView where the selection happened
* #param position The position of the view in the adapter
* #param id The row id of the item that is selected
*/
void onItemSelected(ComboBoxView parent, int position, long id);
/**
* Callback method to be invoked when the selection disappears from this
* view. The selection can disappear for instance when touch is activated
* or when the adapter becomes empty.
*
* #param parent The ComboBoxView that now contains no selected item.
*/
void onNothingSelected(ComboBoxView parent);
}
public void setValuesAsString(final List<String> newValues) {
setValuesAsString(newValues, 0);
}
public void setValuesAsString(final List<String> newValues, int initialValue) {
List<CharSequence> result = new ArrayList<CharSequence>(newValues.size());
for(String value : newValues) {
result.add(value);
}
setValues(result, initialValue);
}
public void setValues(final List<CharSequence> newValues) {
setValues(newValues, 0);
}
public void setValues(final List<CharSequence> newValues, int initialValue) {
if((initialValue >= newValues.size()) || (initialValue < -1)) {
IllegalArgumentException ex = new IllegalArgumentException("Invalid value for initialValue");
LOG.error(LOG.SOURCE.UI, "Invalid",ex);
throw ex;
}
// Prepare the list of elements:
// NOTE: The last item in ComboBoxArrayAdapter must be empty. Items should also contain the
// same number of lines as the "tallest" entry:
final List<CharSequence> finalValues = new ArrayList<CharSequence>(newValues.size());
finalValues.addAll(newValues);
int maxLines = 1;
for(CharSequence text : newValues) {
final String[] lines = text.toString().split("\r\n|\r|\n");
maxLines = Math.max(maxLines, lines.length);
}
finalValues.add("");
// Prepare spinner:
final ComboBoxArrayAdapter adapter = new ComboBoxArrayAdapter(this.getContext(), R.layout.view_combo_box_item, finalValues);
adapter.setDropDownViewResource(R.layout.view_combo_box_item_dropdown);
adapter.setMaxLines(maxLines);
mSpinner.setOnItemSelectedListener(null);
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
boolean firstSelection = true;
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (mListener != null) {
int index = (position >= (mSpinner.getCount() - 1)) ? -1 : position;
mListener.onItemSelected(ComboBoxView.this, index, id);
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
if (mListener != null) {
mListener.onNothingSelected(ComboBoxView.this);
}
}
});
if (mListener != null) {
mListener.onNothingSelected(this);
}
// Set initial selection:
if(initialValue != -1) {
mSpinner.setSelection(initialValue);
} else {
mSpinner.setSelection(newValues.size());
}
}
public void setOnItemSelectedListener(final OnItemSelectedListener listener) {
mListener = listener;
}
public int getSelectedItem() {
int result = mSpinner.getSelectedItemPosition();
if(result >= mSpinner.getCount()) {
result = -1;
}
return result;
}
Spinner
Example Result
Thanks in advance.
I finally fixed this!
The android property clickable was set to false, but the click behaviour was performed in the ComboBoxView.java file on the following code:
private final OnClickListener onClick = new OnClickListener() {
#Override
public void onClick(View v) {
mSpinner.performClick();
}
};
This was working everywhere (devices and emulators) except on Samsung devices with Android 5.0. This I couldn't figure out why.
After I changed the cliclabke property to true it started working.
android:clickable="true"
Thanks.

Custom View children are null after inflating the view in Android

I am working on an Android app. I have a custom view and layout as follows:
<com.hello.view.card.inner.SimpleCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_simple_linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/simple_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</com.hello.view.card.inner.SimpleCardView>
And this is the Java class:
public class SimpleCardView extends LinearLayout {
protected SimpleCard card = null;
protected TextView textView;
public SimpleCardView(Context context) {
super(context);
init(context);
}
public SimpleCardView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SimpleCardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
protected void init(Context context) {
textView = (TextView)findViewById(R.id.simple_label);
}
public void setCard(SimpleCard card) {
this.card = card;
textView.setText(card.getMessage());
}
}
And this is how I am inflating the view (I tried both following calls):
SimpleCardView view = (SimpleCardView)inflater.inflate(R.layout.card_simple, null);
//SimpleCardView view = (SimpleCardView)inflater.inflate(R.layout.card_simple, parent);
view.setCard(card);
The problem I am having is when view.setCard(card) is called, I see that textView is null, even though I am expecting it to be set in the init(..) method. Can anyone tell me what it not being set correctly? Thanks in advance.
Thank you for your answers. It turns out init(context) should not be called in the constructor. The right place to call it is in onFinishInflate(). The following change helped fix it:
public class SimpleCardView extends LinearLayout {
protected SimpleCard card = null;
protected TextView textView;
public SimpleCardView(Context context) {
super(context);
}
public SimpleCardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SimpleCardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
init(getContext());
}
protected void init(Context context) {
textView = (TextView)findViewById(R.id.simple_label);
}
public void setCard(SimpleCard card) {
this.card = card;
textView.setText(card.getMessage());
}
}
Instead of using root element
com.hello.view.card.inner.SimpleCardView
try using
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="#+id/simple_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</merge>
then, in your init method
LayoutInflater.from(context).inflate(R.layout.card_simple, this);
setOrientation(LinearLayout.VERTICAL);
textView = (TextView)findViewById(R.id.simple_label);
When you use the view in other layouts, that's where you will want to put
<com.hello.view.card.inner.SimpleCardView />
and any properties that it needs, its id, its width/height, etc.

Categories