LukSN
LukSN

Reputation: 43

Creating own FrameLayout class doesn't work

I would like to create a own FrameLayout class where I can cancel the toch event but the app crashes everytime directly with an error message.

I ran the same code with the normal FrameLayout and I got no crash. So the app crashes not because of another reason.

The FrameLayout class:

package com.example.motivationsappbetter;

import android.content.Context;
import android.support.annotation.NonNull;
import android.view.MotionEvent;
import android.widget.FrameLayout;

public class MainFrameLayout extends FrameLayout {
    private boolean canTouch = true;

    public MainFrameLayout(@NonNull Context context) {
        super(context);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (canTouch) 
            return super.onInterceptTouchEvent(ev);
        else 
            return true;
    }

    public void setCanTouch(boolean b){
        canTouch = b;
    }
}

MainActivity:

public class MainActivity extends AppCompatActivity {

    MainFrameLayout mainFrame;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mainFrame = findViewById(R.id.main_frame);
        mainFrame.getForeground().setAlpha(0);
    }
}

The activity_main.xml file:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.motivationsappbetter.MainFrameLayout
        android:id="@+id/main_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include
            layout="@layout/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <FrameLayout
            android:id="@+id/frameLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="56dp"
            android:layout_marginBottom="56dp">

        </FrameLayout>

        <android.support.design.widget.BottomNavigationView
            android:id="@+id/navigation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:background="?android:attr/windowBackground"
            app:labelVisibilityMode="unlabeled"
            app:menu="@menu/navigation"
            tools:layout_editor_absoluteY="675dp">

        </android.support.design.widget.BottomNavigationView>

    </com.example.motivationsappbetter.MainFrameLayout>

    <io.github.yavski.fabspeeddial.FabSpeedDial
        android:id="@+id/fabspeeddial"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="false"
        android:layout_alignParentBottom="false"
        android:layout_gravity="bottom|center"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="3dp"
        app:elevation="10dp"
        app:fabGravity="bottom_end"
        app:fabMenu="@menu/fab_menu"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"></io.github.yavski.fabspeeddial.FabSpeedDial>


</android.support.constraint.ConstraintLayout>

That's the error message:

2019-10-07 16:20:11.624 25601-25601/com.example.motivationsappbetter E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.motivationsappbetter, PID: 25601
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.motivationsappbetter/com.example.motivationsappbetter.MainActivity}: android.view.InflateException: Binary XML file line #11: Binary XML file line #11: Error inflating class com.example.motivationsappbetter.MainFrameLayout
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2793)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2864)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1567)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:156)
        at android.app.ActivityThread.main(ActivityThread.java:6523)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
     Caused by: android.view.InflateException: Binary XML file line #11: Binary XML file line #11: Error inflating class com.example.motivationsappbetter.MainFrameLayout
     Caused by: android.view.InflateException: Binary XML file line #11: Error inflating class com.example.motivationsappbetter.MainFrameLayout
     Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
        at java.lang.Class.getConstructor0(Class.java:2204)
        at java.lang.Class.getConstructor(Class.java:1683)
        at android.view.LayoutInflater.createView(LayoutInflater.java:625)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:798)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:738)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:869)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:832)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:518)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:426)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:377)
        at android.support.v7.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)
        at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
        at com.example.motivationsappbetter.MainActivity.onCreate(MainActivity.java:59)
        at android.app.Activity.performCreate(Activity.java:6915)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2746)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2864)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1567)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:156)
        at android.app.ActivityThread.main(ActivityThread.java:6523)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)

I'll be happy about helpful answers :P

PS: Sorry for my bad english

Upvotes: 2

Views: 415

Answers (2)

Richard Le Mesurier
Richard Le Mesurier

Reputation: 29724

The exception gives you the answer in the "Cause". It says that the method is not found for the constructor that takes Context and AttrubuteSet.

Caused by: java.lang.NoSuchMethodException: [class android.content.Context, interface android.util.AttributeSet]

Android uses different constructors for different versions - when making custom view classes, you need to include overrides for all of them:

public FrameLayout(@NonNull Context context) {...}

public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {...}

public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
        @AttrRes int defStyleAttr) {...}

public FrameLayout(@NonNull Context context, @Nullable AttributeSet attrs,
        @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {...}

This way your code will run across all versions of Android, and choose the correct constructor for the version.


See completed class that shows all required methods overridden given in mohammadReza Abiri's answer

Upvotes: 1

mohammadReza Abiri
mohammadReza Abiri

Reputation: 1799

The custom view must have minimum one of the required public constructor that takes in Context,AttributeSet arguments :

public class MainFrameLayout extends FrameLayout {
    private boolean canTouch = true;

    public MainFrameLayout(@NonNull Context context) {
        super(context);
    }

    public MainFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MainFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MainFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (canTouch)
            return super.onInterceptTouchEvent(ev);
        else
            return true;
    }


    public void setCanTouch(boolean b) {
        canTouch = b;
    }
}

Upvotes: 2

Related Questions