Android - 创建自定义复合组件

时间:2014-04-04 12:05:41

标签: java android android-custom-view custom-component custom-view

我几周前开始使用Android编码,在此之前我从未使用oop(我有一些c背景和微控制器嵌入c等),因此我可能会认为这个想法完全错误,但是我需要帮助才能继续:

我创建了一个示例活动,用作一个完美符合我意图的UI。之后我想用它作为未来设计的定制化合物,所以我试图做出改变,但无法弄清楚。该化合物有3个textviews和2个按钮。我还实现了在按钮旁边使用的手势(所以我可以向上或向下滚动来改变值)。

现在当我使用这个自定义化合物时,我收到一个错误。我无法理解为什么。

这里是我的复合布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/CustomTouchPickerLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".CustomTouchPickerActivity" >

<TextView
    android:id="@+id/textViewMid"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/textViewTop"
    android:clickable="true"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:onClick="onClickMid"
    android:paddingBottom="20sp"
    android:paddingTop="20sp"
    android:textSize="45sp" 
    android:text="Mid"
    android:layout_centerHorizontal="true"/>

<TextView
    android:id="@+id/textViewBot"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/textViewMid"
    android:textSize="22sp" 
    android:text="Bot"
    android:layout_centerHorizontal="true"/>

<TextView
    android:id="@+id/textViewTop"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/textViewBot"
    android:layout_marginTop="52dp"
    android:textSize="22sp" 
    android:text="Top"
    android:layout_centerHorizontal="true"/>

<Button
    android:id="@+id/buttonTop"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="OnClickButtonTop"
    android:text="Up" 
    android:layout_centerHorizontal="true"/>

<Button
    android:id="@+id/buttonBot"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/textViewBot"
    android:layout_centerHorizontal="true"
    android:onClick="OnClickButtonBot"
    android:text="Down" />

这是我的化合物的.java文件:

package com.vestel.customtouchpicker;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class CustomTouchPicker extends RelativeLayout {

public int count_sag=0;
public int count_sol=0;
public int count_button_sol=0;
public int count_button_sag=0;
private GestureDetector gestureDetector;




public CustomTouchPicker(Context context, AttributeSet attrs) {
    super(context,attrs);

    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.activity_custom_touch_picker,this);

    gestureDetector = new GestureDetector(new SwipeGestureDetector());

    TextView textViewTop = (TextView)findViewById(R.id.textViewTop);
    TextView textViewBot = (TextView)findViewById(R.id.textViewBot);
    TextView textViewMid = (TextView)findViewById(R.id.textViewMid);

    Button buttonTop = (Button) findViewById(R.id.buttonTop);
    Button buttonBot = (Button) findViewById(R.id.buttonBot);

    textViewTop.setVisibility(View.INVISIBLE);
    textViewBot.setVisibility(View.INVISIBLE);

    buttonTop.setVisibility(Button.INVISIBLE);
    buttonBot.setVisibility(Button.INVISIBLE);

    textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");

}
private class SwipeGestureDetector extends SimpleOnGestureListener {
    // Swipe properties, you can change it to make the swipe
    // longer or shorter and speed
    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 200;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {
        try {
            float diffAbs = Math.abs(e1.getY() - e2.getY());
            float diff = e1.getX() - e2.getX();
            float diff_y = e1.getY() - e2.getY();
            float diffAbs_x = Math.abs(e1.getX() - e2.getY());

            TextView textViewTop = (TextView)findViewById(R.id.textViewTop);
            // down swipe
            if(textViewTop.getVisibility()==0){
                if (e1.getY()>e2.getY()) {
                    if(diff_y>20)
                    {
                        count_button_sol=count_button_sol+1;
                    }
                    CustomTouchPicker.this.onDownSwipe();



                }
                // up swipe
                else if (e1.getY()<e2.getY()) 
                {
                    if(-diff_y>20){
                        count_button_sol=count_button_sol+1;
                    }
                    CustomTouchPicker.this.onUpSwipe();
                }
            } 
        }catch (Exception e) {
            Log.e("YourActivity", "Error on gestures");
        }
        return false;
    }   
}
public void onClickMid(View view) 
{
    count_sol=count_sol+1;
    if(count_sol%2==1){
        TextView textViewTop = (TextView)findViewById(R.id.textViewTop);
        TextView textViewBot = (TextView)findViewById(R.id.textViewBot);            

        Button buttonTop = (Button) findViewById(R.id.buttonTop);
        Button buttonBot = (Button) findViewById(R.id.buttonBot);           

        textViewTop.setVisibility(View.VISIBLE);
        textViewBot.setVisibility(View.VISIBLE);

        buttonTop.setVisibility(Button.VISIBLE);
        buttonBot.setVisibility(Button.VISIBLE);

        textViewBot.setAlpha(0.2f);
        textViewTop.setAlpha(0.2f);
    }
    else
    {
        TextView textViewTop = (TextView)findViewById(R.id.textViewTop);
        TextView textViewBot = (TextView)findViewById(R.id.textViewBot);

        Button buttonTop = (Button) findViewById(R.id.buttonTop);
        Button buttonBot = (Button) findViewById(R.id.buttonBot);

        textViewTop.setVisibility(View.INVISIBLE);
        textViewBot.setVisibility(View.INVISIBLE);

        buttonTop.setVisibility(Button.INVISIBLE);
        buttonBot.setVisibility(Button.INVISIBLE);
    }
}
public void OnClickButtonTop (View view){

    TextView textViewTop = (TextView)findViewById(R.id.textViewTop);        
    TextView textViewBot = (TextView)findViewById(R.id.textViewBot);
    TextView textViewMid = (TextView)findViewById(R.id.textViewMid);

    switch (count_button_sol%4)
    {       
    case 0: textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");
    break;
    case 1: textViewTop.setText("4°");
    textViewMid.setText("6°");
    textViewBot.setText("8°");
    break;
    case 2: textViewTop.setText("6°");
    textViewMid.setText("8°");
    textViewBot.setText("2°");
    break;
    case 3: textViewTop.setText("8°");
    textViewMid.setText("2°");
    textViewBot.setText("4°");
    break;
    default:textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");
    break;
    }
    count_button_sol=count_button_sol+1;
}
public void OnClickButtonBot (View view){

    TextView textViewTop = (TextView)findViewById(R.id.textViewTop);        
    TextView textViewBot = (TextView)findViewById(R.id.textViewBot);
    TextView textViewMid = (TextView)findViewById(R.id.textViewMid);

    switch (count_button_sol%4)
    {

    case 3: textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");
    break;
    case 2: textViewTop.setText("4°");
    textViewMid.setText("6°");
    textViewBot.setText("8°");
    break;
    case 1: textViewTop.setText("6°");
    textViewMid.setText("8°");
    textViewBot.setText("2°");
    break;
    case 0: textViewTop.setText("8°");
    textViewMid.setText("2°");
    textViewBot.setText("4°");
    break;
    default:textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");
    break;
    }
    count_button_sol=count_button_sol+1;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
    if (gestureDetector.onTouchEvent(event)) 
    {
        return true;
    }
    return super.onTouchEvent(event);
}


private void onDownSwipe() 
{
    TextView textViewTop = (TextView)findViewById(R.id.textViewTop);
    TextView textViewBot = (TextView)findViewById(R.id.textViewBot);
    TextView textViewMid = (TextView)findViewById(R.id.textViewMid);

    switch (count_button_sol%4){
    case 0: textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");
    break;
    case 1: textViewTop.setText("4°");
    textViewMid.setText("6°");
    textViewBot.setText("8°");
    break;
    case 2: textViewTop.setText("6°");
    textViewMid.setText("8°");
    textViewBot.setText("2°");
    break;
    case 3: textViewTop.setText("8°");
    textViewMid.setText("2°");
    textViewBot.setText("4°");
    break;
    default:textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");
    break;
    }
}       
private void onUpSwipe() {
    TextView textViewTop = (TextView)findViewById(R.id.textViewTop);
    //          textViewTop.setAlpha(0.5f);
    TextView textViewBot = (TextView)findViewById(R.id.textViewBot);
    TextView textViewMid = (TextView)findViewById(R.id.textViewMid);
    //          textViewBot.setAlpha(0.5f);
    switch (count_button_sol%4){
    case 3: textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");
    break;
    case 2: textViewTop.setText("4°");
    textViewMid.setText("6°");
    textViewBot.setText("8°");
    break;
    case 1: textViewTop.setText("6°");
    textViewMid.setText("8°");
    textViewBot.setText("2°");
    break;
    case 0: textViewTop.setText("8°");
    textViewMid.setText("2°");
    textViewBot.setText("4°");
    break;
    default:textViewTop.setText("2°");
    textViewMid.setText("4°");
    textViewBot.setText("6°");
    break;

    }
}

}

这是我测试的主要活动布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<com.vestel.customtouchpicker
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />

</RelativeLayout>

这里是MainActivity.java

package com.vestel.customtouchpicker;

import android.app.Activity;
import android.os.Bundle;


public class MainActivity extends Activity {

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



}

和android清单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.vestel.customtouchpicker"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="11"
    android:targetSdkVersion="19" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="com.vestel.customtouchpicker.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>

最后是我的logcat

    04-04 14:41:59.049: E/Trace(31339): error opening trace file: No such file or directory (2)
04-04 14:41:59.319: E/AndroidRuntime(31339): FATAL EXCEPTION: main
04-04 14:41:59.319: E/AndroidRuntime(31339): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.vestel.customtouchpicker/com.vestel.customtouchpicker.MainActivity}: android.view.InflateException: Binary XML file line #12: Error inflating class com.vestel.customtouchpicker
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2351)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.ActivityThread.access$600(ActivityThread.java:151)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1331)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.os.Handler.dispatchMessage(Handler.java:99)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.os.Looper.loop(Looper.java:155)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.ActivityThread.main(ActivityThread.java:5454)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at java.lang.reflect.Method.invokeNative(Native Method)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at java.lang.reflect.Method.invoke(Method.java:511)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1029)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:796)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at dalvik.system.NativeStart.main(Native Method)
04-04 14:41:59.319: E/AndroidRuntime(31339): Caused by: android.view.InflateException: Binary XML file line #12: Error inflating class com.vestel.customtouchpicker
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:698)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:363)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.Activity.setContentView(Activity.java:1912)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at com.vestel.customtouchpicker.MainActivity.onCreate(MainActivity.java:12)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.Activity.performCreate(Activity.java:5066)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1101)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2307)
04-04 14:41:59.319: E/AndroidRuntime(31339):    ... 11 more
04-04 14:41:59.319: E/AndroidRuntime(31339): Caused by: java.lang.ClassNotFoundException: com.vestel.customtouchpicker
04-04 14:41:59.319: E/AndroidRuntime(31339):    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.view.LayoutInflater.createView(LayoutInflater.java:552)
04-04 14:41:59.319: E/AndroidRuntime(31339):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
04-04 14:41:59.319: E/AndroidRuntime(31339):    ... 21 more

顺便说一句,如果你直接使用代码作为活动它可以工作(当然我删除了一些像“setContentView”等等的行

2 个答案:

答案 0 :(得分:0)

您在主要活动布局中缺少您的班级名称。它无法找到类com.vestel.customtouchpicker,这只是自定义组件的包名而不是类名。在主要活动布局中将完全限定名称设为com.vestel.customtouchpicker.CustomTouchPicker,它应该有效。

更改为:

<com.vestel.customtouchpicker.CustomTouchPicker
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
/>

编辑:这是ClassNotFoundException的答案,我没有检查你的所有代码。所以可能还有另一个问题。

答案 1 :(得分:0)

我猜这个错误是由以下两行引起的:

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.activity_custom_touch_picker,this);

因为context.getSystemService中的“context”可能会引发异常。 可能你可以使用

context.getApplicationContext().getSystemService

因为您试图使用活动之外的上下文