[2013-06-27 16:25:11 - login] No Launcher activity found!
[2013-06-27 16:25:11 - login] The launch will only sync the application package on the device!
当创建一个login活动的时候报上面的错误。然后程序安装成功,但是不启动。
解决办法是:
到AndroidManifest.xml文件添加Launcher,仿照蓝色的代码就可以了:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.login.LoginActivity"
android:label="@string/app_name"
android:windowSoftInputMode="adjustResize|stateVisible" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
1. 一个界面布局,list有一级跟二级目录,用到ExpandableListView。使用此ListView,需要定义一个界面布局,一个一级目录布局和一个二级目录布局。可使用SimpleExpandableListAdapter去适配。要更多功能,比如修改一级目录图标,可自定义adapter。
要去掉ExpandableListView一级目录自带图标,只需设置属性
android:groupIndicator="@null"
(1)遇到问题:ExpandableListView一级目录自带的图标修改成自定义图标出错
原因:SimpleExpandableListAdapter会将所有传进来的控件转换成TextView,导致ClassCastException。
这是SimpleExpandableListAdapter的内部实现方法
private void bindView(View view, Map<String, ?> data, String[] from, int[] to) { int len = to.length; for (int i = 0; i < len; i++) { TextView v = (TextView)view.findViewById(to[i]); if (v != null) { v.setText((String)data.get(from[i])); } } }
这样修改bindView方法即可
public class MyExpandListAdapter extends BaseExpandableListAdapter { private ViewBinder mViewBinder; private List<? extends Map<String, ?>> mGroupData; private int mExpandedGroupLayout; private int mCollapsedGroupLayout; private String[] mGroupFrom; private int[] mGroupTo; private List<? extends List<? extends Map<String, ?>>> mChildData; private int mChildLayout; private int mLastChildLayout; private String[] mChildFrom; private int[] mChildTo; private LayoutInflater mInflater; public MyExpandListAdapter(Context context, List<? extends Map<String, ?>> groupData, int groupLayout, String[] groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData, int childLayout, String[] childFrom, int[] childTo) { this(context, groupData, groupLayout, groupLayout, groupFrom, groupTo, childData, childLayout, childLayout, childFrom, childTo); } public MyExpandListAdapter(Context context, List<? extends Map<String, ?>> groupData, int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData, int childLayout, String[] childFrom, int[] childTo) { this(context, groupData, expandedGroupLayout, collapsedGroupLayout, groupFrom, groupTo, childData, childLayout, childLayout, childFrom, childTo); } public MyExpandListAdapter(Context context, List<? extends Map<String, ?>> groupData, int expandedGroupLayout, int collapsedGroupLayout, String[] groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData, int childLayout, int lastChildLayout, String[] childFrom, int[] childTo) { mGroupData = groupData; mExpandedGroupLayout = expandedGroupLayout; mCollapsedGroupLayout = collapsedGroupLayout; mGroupFrom = groupFrom; mGroupTo = groupTo; mChildData = childData; mChildLayout = childLayout; mLastChildLayout = lastChildLayout; mChildFrom = childFrom; mChildTo = childTo; mInflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public Object getChild(int groupPosition, int childPosition) { return mChildData.get(groupPosition).get(childPosition); } public long getChildId(int groupPosition, int childPosition) { return childPosition; } /** * Instantiates a new View for a child. * * @param isLastChild * Whether the child is the last child within its group. * @param parent * The eventual parent of this new View. * @return A new child View */ public View newChildView(boolean isLastChild, ViewGroup parent) { return mInflater.inflate((isLastChild) ? mLastChildLayout : mChildLayout, parent, false); } public int getChildrenCount(int groupPosition) { return mChildData.get(groupPosition).size(); } public Object getGroup(int groupPosition) { return mGroupData.get(groupPosition); } public int getGroupCount() { return mGroupData.size(); } public long getGroupId(int groupPosition) { return groupPosition; } /** * Instantiates a new View for a group. * * @param isExpanded * Whether the group is currently expanded. * @param parent * The eventual parent of this new View. * @return A new group View */ public View newGroupView(boolean isExpanded, ViewGroup parent) { return mInflater.inflate((isExpanded) ? mExpandedGroupLayout : mCollapsedGroupLayout, parent, false); } public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } public boolean hasStableIds() { return true; } private void bindView(View view, Map<String, ?> data, String[] from, int[] to) { int len = to.length; boolean isBound = false; for (int i = 0; i < len; i++) { final View v = view.findViewById(to[i]); if (v != null) { final Object _data = data.get(from[i]); String text = _data == null ? "" : data.toString(); if (text == null) { text = ""; } if (mViewBinder != null) {// 如果Binder不为空,使用Binder进行处理 isBound = mViewBinder.setViewValue(v, data.get(from[i]), text); } if (!isBound) {// 如果Binder跳过,使用原来的方法进行处理 TextView _v = (TextView) v; _v.setText((String) data.get(from[i])); } } } } public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { View v; if (convertView == null) { v = newGroupView(isExpanded, parent); } else { v = convertView; } bindView(v, mGroupData.get(groupPosition), mGroupFrom, mGroupTo); return v; } public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { View v; if (convertView == null) { v = newChildView(isLastChild, parent); } else { v = convertView; } bindView(v, mChildData.get(groupPosition).get(childPosition), mChildFrom, mChildTo); return v; } public void setViewBinder(ViewBinder mViewBinder) { this.mViewBinder = mViewBinder; } /** * 提供视图渲染的绑定器 * * @author Atomic */ public static interface ViewBinder { boolean setViewValue(View view, Object data, String textRepresentation); }
代码摘自http://www.eoeandroid.com/code/2011/1202/220.html
修改完以后,可以在Activity代码中像SimpleExpandableListAdapter一样使用。在一级目录的布局中就可以新添加ImageView属性,使用自定义的图标了。
public class ProjectTableExActivity extends Activity { private ExpandableListView lv; // private SimpleExpandableListAdapter adapter; private MyExpandListAdapter adapter1; private List<List<Map<String, Object>>> child; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.project_table_expandlist); child = new ArrayList<List<Map<String, Object>>>(); lv = (ExpandableListView) findViewById(R.id.projectTabExpandList); adapter1 = new MyExpandListAdapter(this, groupData(new String[] { "你好","我好","大家好" }), R.layout.project_table_item, new String[] { "img", "text" }, new int[] { R.id.item_img2, R.id.item_txt3 }, child, R.layout.project_table_child, new String[] {}, new int[] {}); adapter1.setViewBinder(new MyExpandListAdapter.ViewBinder() { @Override public boolean setViewValue(View view, Object data, String textRepresentation) { switch (view.getId()) { case R.id.item_img2: {//要替换成的图标的Id if (view instanceof ImageView) { ImageView _view = (ImageView) view; if (data instanceof Integer) { _view.setImageResource((Integer) data); } else if (data instanceof Drawable) { _view.setImageDrawable((Drawable) data); } else { throw new IllegalArgumentException( "The Data is Not a Drawable Or Resource Id!"); } } return true; } } return false; } }); lv.setAdapter(adapter1); } private List<? extends Map<String, ?>> groupData(String[] str) { ArrayList<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); // Field field; try { for (int i = 0; i < str.length; i++) { Resources res = getResources(); int lable = res.getIdentifier("cv_lable" + (i + 1), "drawable", getPackageName()); /* * field = R.drawable.class.getField("R.drawable.cv_lable" + (i * + 1)); int lable = field.getInt(new R.drawable()); */ Map map = new HashMap<String, Object>(); map.put("img", lable); map.put("text", str[i]); list.add(map); List<Map<String, Object>> child1 = new ArrayList<Map<String, Object>>(); Map<String, Object> childdata = new HashMap<String, Object>(); child1.add(childdata); child.add(child1); } } catch (Exception e) { e.printStackTrace(); } return list; } }
注意取得lable的方法
(2)遇到问题:二级目录打不开
原因:在一级目录中有按钮控件存在
给他添加属性
android:focusable="false"
即可
2.自定义EditText的背景图和边框
背景图可直接修改background图片
新建类继承自EditText,绘制边框
public class MyEditText extends EditText { public MyEditText(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setStyle(Style.STROKE); paint.setStrokeWidth(2); if (this.isFocused() == true) paint.setColor(Color.parseColor("#D9DAD4")); else paint.setColor(Color.parseColor("#D9DAD4")); canvas.drawRoundRect( new RectF(this.getScrollX(), this.getScrollY(), this .getWidth() + this.getScrollX(), this.getHeight() + this.getScrollY() ), 3, 3, paint); super.onDraw(canvas); } }
代码源自网络
在xml中引用时直接使用这个自定义的EditText即可【全类名】
activity是与用户进行交互的屏幕,比如:打电话,拍照,发送邮件,浏览地图。每个activity被赋予了一个窗口,在这个窗口上可以勾画用户交互界面。窗口可以填充整个屏幕,也可以比屏幕小,或者悬浮在其它窗口的上面。
一个应用通常包含多个activity,各个activity彼此松散地进行关联。其中有一个activity被指定为main activity,当应用第一次启动的时候,main activity会出现在用户面前。为了执行不同的动作,每个activity都可以启动其它的activity。每次启动一个新的activity,原来的activity会被停止,但是系统仍然会把它保留在back stack中,同时新启动的activity也会压入back stack中,并获得用户焦点。当用户执行完操作,点击后退的时候,当前activity会被弹出back stack,并被destroy,然后前一个activity继续运行。
每个activity都存在生命周期,生命周期中包括各种状态,每当状态发生变化的时候,系统都会调用相应的生命周期回调方法,在回调方法中,给用户提供做一些事情的机会。比如被stop的时候,你的activity应该释放大对象,比如网络连接,数据库连接。当activity被resume的时候,可以重新获取需要的资源并且继续执行之前被中断的动作。这些状态的变化都是activity生命周期的一部分。
创建一个activity
为了创建一个activity,你必须创建一个android.app.Activity类的子类。并且实现回调方法,这样,当activity的生命周期中的状态发生变化的时候,系统可以进行回调。比如:创建,停止,继续,销毁。最重要的方法包括onCreate和onPause。
- onCreate方法中,你应该初始化必要的组件,必须调用setContentView方法来设置activity的用户界面的layout。
- onPause方法,当用户离开activity的时候,会回调此方法。在此方法中,你应该提交需要持久化的变更,因为用户可能不会再回到这个activity。
实现一个用户界面
activity的用户界面由一组继承自android.view.View类的view组成。每个view控制activity窗口中的一个特定的矩形区域,并可以对用户的动作作出响应。比如:一个view可以是一个按钮,当用户点击的时候可以做一系列的动作。
android提供了许多现成的view,你可以用它们来设计和组织你的画面布局。
- widgets:可视可交互的view,比如:button,text field,checkbox,image
- layouts:继承自android.view.ViewGroup类的view。它为子view提供一种布局模式,比如:linear layout,grid layout,relative layout。你也可以通过View或者ViewGroup类的子类来创建自己的widget和layout,然后把它们应用到你的activity中。
定义一个layout的最通用做法是使用一个XML layout 文件,这样你可以把用户界面的设计单独从代码中提取出来,在代码中仅定义activity的各种行为。然后调用setContentView(int layoutResID)方法来指定activity的conent到该XML layout文件。当然,你也可以不使用XML layout文件,而是直接在代码中定义各种View以及ViewGroup,然后把root ViewGroup传递给setContentView(View view)方法。
在manifest文件中声明activity,使用intent filters
<activityandroid:name=".ExampleActivity"android:icon="@drawable/app_icon"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
- action元素指定该activity是应用的main入口点
- category元素指定该activity被追加到系统的应用启动列表中,也就是说允许用户启动该activity。
- 如果你不希望别的应用使用你的activity,那么不需要追加任何其它的intent-filter,当然,在你的应用内部可以使用显式的intent(直接指定包名和类名)来启动activity。
- 在一个应用中,只能有一个activity具有MAIN action和LAUNCHER category。
- 如果你想使用隐式intent(别的应用或者同一应用内部)来启动activity,那么必须为每种intent类型定义一个包含action,category,data的intent-filter。
启动一个activity(不返回结果)
如果要启动的activity在同一个应用的内部,可以采用显式的intent
Intent intent =newIntent(this,SignInActivity.class); startActivity(intent);
如果要启动的activity在另外一个应用的内部,那么只能采用隐式intent
比如:打算发送邮件
Intent intent =newIntent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_EMAIL, recipientArray); startActivity(intent);
recipientArray是一个string数组,存放收件人的email地址。
如果系统通过intent-filter,匹配到多个可以使用的activity的话,会提示用户选择其中的一个。
当邮件发送完成,会回到原来的activity继续运行。
启动一个activity(返回结果)
privatevoid pickContact(){ // Create an intent to "pick" a contact, as defined by the content provider URI Intent intent =newIntent(Intent.ACTION_PICK,Contacts.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT_REQUEST); } @Override protectedvoid onActivityResult(int requestCode,int resultCode,Intent data){ // If the request went well (OK) and the request was PICK_CONTACT_REQUEST if(resultCode ==Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST){ // Perform a query to the contact's content provider for the contact's name Cursor cursor = getContentResolver().query(data.getData(), newString[]{Contacts.DISPLAY_NAME},null,null,null); if(cursor.moveToFirst()){// True if the cursor is not empty int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); String name = cursor.getString(columnIndex); // Do something with the selected contact's name... } } }
从地址簿中选择一个联系人,然后系统会通过回调onActivityResult方法来返回Intent类型的结果数据,然后从contact的content provider中检索出联系人的名字。
关闭一个activity
- 可以通过调用finish()方法结束当前的activity
- 也可以通过调用finish(int requestCode)方法来结束之前通过startActivityForResult(Intent, int requestCode)启动的activity,如果指定的requestCode对应了多个activity,那么所有对应的activity都将被关闭。