在片段中使用CustomView的ClassCastException

时间:2018-10-20 11:35:35

标签: java android

大家好,我正在尝试创建自定义视图,即 SlideButton
所以我的问题是,当我在activity_main 中将我的 customView添加为xml并在 MainActivity 中实现回调时,所有人都认为效果很好(即,我的监听器运行良好)。

但是当我在Fragment中执行相同的操作时,我得到 ClassCastException ,因此我用try / catch init方法包围了我的代码,然后错误消失了。

但是当我运行我的应用程序并按下按钮时,它不会显示任何Toast (即,侦听器在Fragment中不起作用)

这是例外代码

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)

这是我的CustomView类

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();
    }
}

这是fragment.xml中的我的customView

<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>

这是片段中的我的SlideButton侦听器(回调)

 @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();
            }
        }
    }

更新代码

修复ClassCastException 后,出现的第二个问题是,当我单击任何按钮时,btnDown从未被调用。
这是更新代码 MainActivity实现监听器

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更新

 <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类与上述相同

2 个答案:

答案 0 :(得分:0)

主要问题是您要在SlideButton中创建onCreateView的新对象,并在其上设置侦听器,而不是实际实例。要获取实际实例,您需要使用findViewById,但是在xml中您已将ID分配为custom:id,这是组件所需的附加属性。您应该使用android:id="@+id/slideButton"为其分配ID,然后在slideButton1 = view.findViewById(R.id.slideButtton)之类的onCreateView中使用该ID

答案 1 :(得分:0)

更新代码的解决方案,即侦听器现在可用于btnDown

CustomView Listener(Callback) with multiple button and different id