Lokik Soni
Lokik Soni

Reputation: 702

ClassCastException using CustomView in Fragment

Hello everyone I am trying to make my customView i.e SlideButton
So my question is when i am adding my customView as xml in activity_main and implementing callback in MainActivity all thinks works perfectly(i.e my listener is working good).

But when i do this same thing in Fragment then i get ClassCastException so i surround my code with try/catch inside init method then the error has gone.

But when i run my app and press the button does not show any Toast (i.e listener not working in Fragment)

Here is the Exception Code

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.greenlab.hackme.swipebutton, PID: 462
                  java.lang.RuntimeException: Unable to start activity ComponentInfo{com.greenlab.hackme.swipebutton/com.greenlab.hackme.swipebutton.MainActivity}: android.view.InflateException: Binary XML file line #10: Binary XML file line #10: Error inflating class com.greenlab.hackme.slidebutton.SlideButton
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2723)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2784)
                      at android.app.ActivityThread.-wrap12(ActivityThread.java)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1523)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:163)
                      at android.app.ActivityThread.main(ActivityThread.java:6238)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:933)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
                   Caused by: android.view.InflateException: Binary XML file line #10: Binary XML file line #10: Error inflating class com.greenlab.hackme.slidebutton.SlideButton
                   Caused by: android.view.InflateException: Binary XML file line #10: Error inflating class com.greenlab.hackme.slidebutton.SlideButton
                   Caused by: java.lang.reflect.InvocationTargetException
                      at java.lang.reflect.Constructor.newInstance0(Native Method)
                      at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
                      at android.view.LayoutInflater.createView(LayoutInflater.java:652)
                      at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:812)
                      at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:752)
                      at android.view.LayoutInflater.rInflate(LayoutInflater.java:883)
                      at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:846)
                      at android.view.LayoutInflater.inflate(LayoutInflater.java:522)
                      at android.view.LayoutInflater.inflate(LayoutInflater.java:430)
                      at com.greenlab.hackme.swipebutton.ButtonFragment.onCreateView(ButtonFragment.java:28)
                      at android.support.v4.app.Fragment.performCreateView(Fragment.java:2439)
                      at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
                      at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
                      at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
                      at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:802)
                      at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
                      at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
                      at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
                      at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
                      at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3273)
                      at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3229)
                      at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
                      at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:620)
                      at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
                      at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1249)
                      at android.app.Activity.performStart(Activity.java:6883)
                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2686)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2784)
                      at android.app.ActivityThread.-wrap12(ActivityThread.java)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1523)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:163)
                      at android.app.ActivityThread.main(ActivityThread.java:6238)
                      at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:933)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
                   Caused by: java.lang.ClassCastException: com.greenlab.hackme.swipebutton.MainActivity cannot be cast to com.greenlab.hackme.slidebutton.SlideButton$SlideListener
                      at com.greenlab.hackme.slidebutton.SlideButton.init(SlideButton.java:81)
                      at com.greenlab.hackme.slidebutton.SlideButton.<init>(SlideButton.java:51)

Here is my CustomView Class

public class SlideButton extends LinearLayout implements View.OnClickListener
{
    LinearLayout linearLayout;
    TextView centerText;
    ImageButton slidingButton;
    View view;

    TypedArray typedArray;
    //shapes
    GradientDrawable buttonCollapse,buttonExpand,backgroundButton;
    String mAttrText;
    Drawable disabledDrawable,enabledDrawable;
    int mAttrId,mAttrButtonPadding,mAttrTextPadding,
            mAttrTextSize,mAttrTextColor,mAttrRadius,mAttrCollapse,
            mAttrStrokeWidth,mAttrStrokeColor,mAttrExpand,mAttrBackColor,
            mAttrBackStrokeColor,mAttrBackStrokeWidth;

    //it is the variable that says that the button is expand or not.
    private boolean active;
    //it is the initial width of the button. we need to save it so we can back to the initial position.
    private int initialButtonWidth;
    SlideListener listener;

    public SlideButton(Context context) {
        super(context);
        init(context,null,-1,-1);
    }

    public SlideButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, -1, -1);
    }

    public SlideButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr, -1);
    }

    @TargetApi(21)
    public SlideButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs, defStyleAttr, defStyleRes);
    }

    public void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

        attrValue(context,attrs);
        btnCollapse();
        btnExpand();
        backButton();
        dynamicLayout(context);
        dynamicButton(context);
        dynamicTextView(context);
        new ShineEffect(centerText);

        try {
            listener = (SlideListener) context;
        }catch (ClassCastException e){
            e.printStackTrace();
        }
    }

    /*
  -----------------------------------------getting attr values---------------------------------------------------------
     */
    private void attrValue(Context context,AttributeSet attrs){

        typedArray=context.getTheme().obtainStyledAttributes(attrs,R.styleable.SlideButton,0,0);
        try {
            //attribute for id
            mAttrId=typedArray.getResourceId(R.styleable.SlideButton_id,0);

            //attribute for text
            mAttrText = typedArray.getString(R.styleable.SlideButton_text);
            mAttrTextPadding=typedArray.getDimensionPixelSize(R.styleable.SlideButton_textPadding,0);
            mAttrTextSize=typedArray.getDimensionPixelSize(R.styleable.SlideButton_textSize,0);
            mAttrTextColor=typedArray.getColor(R.styleable.SlideButton_textColor, Color.GRAY);

            //attribute for  button
            mAttrButtonPadding =typedArray.getDimensionPixelSize(R.styleable.SlideButton_buttonPadding,0);
            mAttrRadius=typedArray.getDimensionPixelSize(R.styleable.SlideButton_cornerRadius,45);
            mAttrCollapse=typedArray.getColor(R.styleable.SlideButton_collapseColor,Color.WHITE);
            mAttrExpand=typedArray.getColor(R.styleable.SlideButton_expandColor,Color.WHITE);
            disabledDrawable=typedArray.getDrawable(R.styleable.SlideButton_collapseIcon);
            enabledDrawable=typedArray.getDrawable(R.styleable.SlideButton_expandIcon);
            mAttrStrokeColor=typedArray.getColor(R.styleable.SlideButton_strokeColor,Color.parseColor("#ee071a32"));
            mAttrStrokeWidth=typedArray.getDimensionPixelSize(R.styleable.SlideButton_strokeWidth,3);

            //attribute for background
            mAttrBackColor=typedArray.getColor(R.styleable.SlideButton_backColor,Color.parseColor("#ee071a32"));
            mAttrBackStrokeColor=typedArray.getColor(R.styleable.SlideButton_backStrokeColor,Color.WHITE);
            mAttrBackStrokeWidth=typedArray.getDimensionPixelSize(R.styleable.SlideButton_backStrokeWidth,3);
        }
        finally {
            typedArray.recycle();
        }
    }

     /*
  -----------------------------------------btn collapse shape---------------------------------------------------------
     */

    private void btnCollapse(){
        buttonCollapse = new GradientDrawable();
        buttonCollapse.setShape(GradientDrawable.RECTANGLE);
        buttonCollapse.setCornerRadius(mAttrRadius);
        buttonCollapse.setColor(mAttrCollapse);
        buttonCollapse.setStroke(mAttrStrokeWidth,mAttrStrokeColor);
    }

     /*
  -----------------------------------------btn expand shape---------------------------------------------------------
     */

    private void btnExpand(){
        buttonExpand = new GradientDrawable();
        buttonExpand.setShape(GradientDrawable.RECTANGLE);
        buttonExpand.setCornerRadius(mAttrRadius);
        buttonExpand.setColor(mAttrExpand);
        buttonExpand.setStroke(mAttrStrokeWidth,mAttrStrokeColor);
    }

     /*
  -----------------------------------------btn background shape---------------------------------------------------------
     */

    private void backButton(){
        backgroundButton = new GradientDrawable();
        backgroundButton.setShape(GradientDrawable.RECTANGLE);
        backgroundButton.setCornerRadius(mAttrRadius);
        backgroundButton.setColor(mAttrBackColor);
        backgroundButton.setStroke(mAttrBackStrokeWidth,mAttrBackStrokeColor);
    }

     /*
  -----------------------------------------dynamic linear layout---------------------------------------------------------
     */

    private void dynamicLayout(Context context) {
        linearLayout=new LinearLayout(context);
        //LayoutParams are used by views to tell their parents how big the view wants to be for both in width and height
        linearLayout.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        linearLayout.setOrientation(LinearLayout.HORIZONTAL);
        linearLayout.setBackground(backgroundButton);
        linearLayout.setGravity(Gravity.START);
        //add the view to parent layout
        addView(linearLayout);
    }

     /*
  -----------------------------------------dynamic text view---------------------------------------------------------
     */

    private void dynamicTextView(Context context) {
        centerText=new TextView(context);
        centerText.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT));
        centerText.setGravity(Gravity.CENTER);
        centerText.setText(mAttrText);
        centerText.setPadding(mAttrTextPadding,0,0,0);
        centerText.setTextSize(mAttrTextSize);
        centerText.setTextColor(mAttrTextColor);
        linearLayout.addView(centerText);
    }

     /*
  -----------------------------------------dynamic image button--------------------------------------------------------
     */

    private void dynamicButton(Context context) {
       slidingButton=new ImageButton(context);
       LayoutParams params=new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
       params.setMargins(3,3,3,3);
       slidingButton.setLayoutParams(params);
       slidingButton.setImageDrawable(disabledDrawable);
        slidingButton.setId(mAttrId);
       slidingButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
       slidingButton.setPadding(mAttrButtonPadding,mAttrButtonPadding,mAttrButtonPadding,mAttrButtonPadding);
       slidingButton.setBackground(buttonCollapse);
       linearLayout.addView(slidingButton);
       slidingButton.setOnClickListener(this);
    }

     /*
  -----------------------------------------listener---------------------------------------------------------
     */

    @Override
    public void onClick(View view) {

        this.view=view;
        if(active){
            collapseButton();
        }
        else {
            initialButtonWidth=slidingButton.getWidth();
            expandButton();
        }
    }

    public interface SlideListener{
        void onClick(boolean active,View v);
    }

    public void setOnSlideListener(SlideListener listener){
        this.listener=listener;
    }

     /*
  -----------------------------------------expand animation---------------------------------------------------------
     */

    private void expandButton()
    {
        final ValueAnimator widthAnimator = ValueAnimator.ofInt(slidingButton.getWidth(),getWidth()-6);
        widthAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                ViewGroup.LayoutParams params = slidingButton.getLayoutParams();
                params.width = (Integer) widthAnimator.getAnimatedValue();
                slidingButton.setLayoutParams(params);
                slidingButton.setEnabled(false);
            }
        });

        widthAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                active = true;

                if (listener!=null) {
                    listener.onClick(true,view);
                }
                slidingButton.setEnabled(true);
                slidingButton.setImageDrawable(enabledDrawable);
                slidingButton.setBackground(buttonExpand);
            }
        });
        widthAnimator.start();
    }

     /*
  -----------------------------------------collapse animation---------------------------------------------------------
     */

    private void collapseButton() {

        final ValueAnimator widthAnimator = ValueAnimator.ofInt(slidingButton.getWidth(), initialButtonWidth);
        widthAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                ViewGroup.LayoutParams params =  slidingButton.getLayoutParams();
                params.width = (Integer) widthAnimator.getAnimatedValue();
                slidingButton.setLayoutParams(params);
                slidingButton.setEnabled(false);
            }
        });

        widthAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                active = false;

                if(listener!=null){
                    listener.onClick(false,view);
                }
                slidingButton.setEnabled(true);
                if(disabledDrawable!=null){
                    slidingButton.setImageDrawable(disabledDrawable);
                }
                slidingButton.setBackground(buttonCollapse);
            }
        });
        widthAnimator.start();
    }
}

Here is my customView in fragment.xml

<com.greenlab.hackme.slidebutton.SlideButton
        android:layout_width="260dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="100dp"
        custom:id="@+id/btnDown"
        custom:buttonPadding="15dp"
        custom:cornerRadius="25dp"
        custom:collapseColor="@android:color/white"
        custom:expandColor="@android:color/white"
        custom:collapseIcon="@drawable/collapsed"
        custom:expandIcon="@drawable/expanded"
        custom:strokeColor="#ee071a32"
        custom:strokeWidth="3dp"
        custom:backStrokeColor="@android:color/white"
        custom:backColor="#ee071a32"
        custom:backStrokeWidth="2dp"
        custom:text="Tap to Activate"
        custom:textPadding="20dp"
        custom:textSize="8dp"
        custom:textColor="#b3a9a9">
    </com.greenlab.hackme.slidebutton.SlideButton>

Here is my SlideButton Listener(CallBack) in Fragment

 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        view= inflater.inflate(R.layout.fragment_button, container, false);

        slideButton1=new SlideButton(getActivity());
        slideButton2=new SlideButton(getActivity());
        slideButton1.setOnSlideListener(this);
        slideButton2.setOnSlideListener(this);

        return view;
    }

    @Override
    public void onClick(boolean active, View v) {

        if(v.getId()==R.id.btnUp) {

            if(active){
                Toast.makeText(getContext(), "Active Up", Toast.LENGTH_SHORT).show();
            }
            else {
                Toast.makeText(getContext(), "Deactivate Up", Toast.LENGTH_SHORT).show();
            }

        }else if(v.getId()==R.id.btnDown){

            if(active){
                Toast.makeText(getContext(), "Active Down", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(getContext(), "Deactivate Down", Toast.LENGTH_SHORT).show();
            }
        }
    }

Update Code

After fixing ClassCastException the second problem arise is that when i click on any button btnDown is never called.
Here is update code MainActivity implement Listener

public class MainActivity extends AppCompatActivity implements SlideButton.SlideListener {

    SlideButton slideButton1,slideButton2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        slideButton1=findViewById(R.id.btnUp);
        slideButton2=findViewById(R.id.btnDown);

        slideButton1.setOnSlideListener(this);
        slideButton2.setOnSlideListener(this);
    }

    @Override
    public void onClick(boolean active) {

        if(slideButton1.getId()==R.id.btnUp) {

            if(active){
                Toast.makeText(this, "Active Up", Toast.LENGTH_SHORT).show();
            }
            else {
                Toast.makeText(this, "Deactivate Up", Toast.LENGTH_SHORT).show();
            }

        }else if(slideButton2.getId()==R.id.btnDown){

            if(active){
                Toast.makeText(this, "Active Down", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(this, "Deactivate Down", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

activity_main.xml Update

 <com.greenlab.hackme.slidebutton.SlideButton
        android:id="@+id/btnUp"
        android:layout_width="260dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"


        custom:buttonPadding="20dp"
        custom:cornerRadius="45dp"
        custom:collapseColor="@android:color/white"
        custom:expandColor="@android:color/white"
        custom:collapseIcon="@drawable/collapsed"
        custom:expandIcon="@drawable/expanded"
        custom:strokeColor="#ee071a32"
        custom:strokeWidth="3dp"

        custom:backStrokeColor="@android:color/white"
        custom:backColor="#ee071a32"
        custom:backStrokeWidth="2dp"

        custom:text="Tap to Activate"
        custom:textPadding="20dp"
        custom:textSize="8dp"
        custom:textColor="#a39c9c">
    </com.greenlab.hackme.slidebutton.SlideButton>

 <com.greenlab.hackme.slidebutton.SlideButton
        android:id="@+id/btnDown"
        android:layout_width="260dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="100dp"
        custom:buttonPadding="15dp"
        custom:cornerRadius="25dp"
        custom:collapseColor="@android:color/white"
        custom:expandColor="@android:color/white"
        custom:collapseIcon="@drawable/collapsed"
        custom:expandIcon="@drawable/expanded"
        custom:strokeColor="#ee071a32"
        custom:strokeWidth="3dp"
        custom:backStrokeColor="@android:color/white"
        custom:backColor="#ee071a32"
        custom:backStrokeWidth="2dp"
        custom:text="Tap to Activate"
        custom:textPadding="20dp"
        custom:textSize="8dp"
        custom:textColor="#b3a9a9">
    </com.greenlab.hackme.slidebutton.SlideButton>

CustomView class is same as above

Upvotes: 0

Views: 83

Answers (2)

Lokik Soni
Lokik Soni

Reputation: 702

Solution of Update code i.e Listener now working for btnDown

CustomView Listener(Callback) with multiple button and different id

Upvotes: 0

Abdullah Razzaki
Abdullah Razzaki

Reputation: 992

The main problem is that you are creating a new object of SlideButton in onCreateView and setting listeners on it rather than the actual instance. To get the actual instance you need to use findViewById but in your xml you have assigned id as custom:id which is an additional attribute required for your component. You should assign it an id with android:id="@+id/slideButton" and then use that id in the onCreateView like slideButton1 = view.findViewById(R.id.slideButtton)

Upvotes: 1

Related Questions