大家好,我正在尝试创建自定义视图,即 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类与上述相同
答案 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