Android API Guide 之 User Interface笔记

简介:   一、Layouts 1  在XML中,标签名对应于代码中的类名,属性名对应于代码中的方法名 2 android:id="@+id/start" @ 让XML解析器知道后面的字符串应该解析为一个 Resource ID + 表明是自己定义的新的ID,不是系统built-...
 
一、Layouts

在XML中,标签名对应于代码中的类名,属性名对应于代码中的方法名

2 android:id="@+id/start"
@ 让XML解析器知道后面的字符串应该解析为一个 Resource ID
+ 表明是自己定义的新的ID,不是系统built-in的,
如果使用系统的应该是这样android:id="@android:id/empty"

3 ViewGroup.LayoutParams
这是一个类,只不过是一个内部静态类,不过在这里把它当做一个类即可.
一个View应该具有一个ViewGroup.LayoutParams对象,并对这个对象进行
适当的初始化,这样它的parent才能知道如何放置它.
想一想当我们在XML中定义一个按钮时它总是具有一个 layout_width/layout_height属性,
这就相当于
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(layout_width,layout_height);
View.setLayoutParams(layoutParams);

View.getLeft()/View.getTop()
The size of a view is expressed with a width and a height. 
A view actually possess two pairs of width and height values. 
measured width/height --> getMeasuredWidth/Height() //在parent内一个View有多大
width/height --> getWidth/Height() //一个View真正的尺寸
View可以有padding --> setPadding(int,int,int,int) getPaddingLeft/Top/Right/Bottom()
View可以有margin,但是是通过 ViewGroup.MarginLayoutParams 来设置的.

4
注意像 ListView/GridView 都是ViewGroup

5 如果设置一个View的background
android:background     setBackgroundResource(int)     A drawable to use as the background.
对于按钮又可以在 /res/drawable 目录下定义如下xml文件:

custom_background.xml (把此文件当做一个 drawable 来用)

[html]  view plain copy
  1. <!-- 具体定义此文件的语法可以在 Resource Type 相关的API Guide中找到 -->  
  2. <?xml version="1.0" encoding="utf-8"?>  
  3. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  4.     <item android:drawable="@drawable/button_pressed"  
  5.           android:state_pressed="true" />  
  6.     <item android:drawable="@drawable/button_focused"  
  7.           android:state_focused="true" />  
  8.     <item android:drawable="@drawable/button_default" />  
  9. </selector>  
6 EditView 常用设置
android:inputType 用来指定是数字,email,password等输入类型
android:textmultiLine 指定EditView可以有多行
android:imeOptions 指定一个按钮在EditView的末尾,以便用户输入完成后点击

7
AutoCompleteTextView 需要设置一个 Adapter

8 Input Events
View类内部定义的事件接口有:(注意有些方法返回的是boolean型,搞明白为什么)
View.OnClickListener --> public void onClick(View v)
View.OnLongClickListener --> boolean onLongClick (View v)
View.OnFocusChangeListener --> void onFocusChange (View v, boolean hasFocus)
View.OnKeyListener --> boolean onKey (View v, int keyCode, KeyEvent event)
View.OnTouchListener -->  boolean onTouch (View v, MotionEvent event)
//这个事件是在onLongClick的情况下发生的
View.OnCreateContextMenuListener 
-->void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)

9 Touch Mode
For a touch-capable device, once the user touches the screen, 
the device will enter touch mode.

Any time a user hits a directional key or scrolls with a trackball, the device will exit
touch mode, and find a view to take focus.

10 Focus
Focus movement 有一个普遍的算法,即会把焦点移动到离现在View最近的那个View;但有时这种算法
并不适合开发者,开发者可以通过以下方法声明焦点转移的顺序.

[html]  view plain copy
  1. <LinearLayout android:orientation="vertical"  
  2.     ... >  
  3.   <Button android:id="@+id/top"  
  4.           android:nextFocusUp="@+id/bottom"  
  5.           ... />  
  6.   <Button android:id="@+id/bottom"  
  7.           android:nextFocusDown="@+id/top"  
  8.           ... />  
  9. </LinearLayout>  
共四种:nextFocusDown, nextFocusLeft, nextFocusRight, and nextFocusUp
和焦点相关的属性还有:
android:focusable
android:focusableInTouchMode

requestFocus()

二、Menus
三种菜单: 
Options menu(用Menu按键触发,android3.0已经取消这个按键,用action bar代替)
Context menu
Popup menu

1 定义一个Menu in XML
game_menu.xml:

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <menu xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <item android:id="@+id/new_game"  
  4.           android:icon="@drawable/ic_new_game"  
  5.           android:title="@string/new_game"  
  6.           <!-- 此属性和action bar相关 -->  
  7.           android:showAsAction="ifRoom">  
  8.           <!-- item里可以嵌套menu -->  
  9.           <menu>  
  10.             ...  
  11.           </menu>  
  12.     </item>  
  13.     <item android:id="@+id/help"  
  14.           android:icon="@drawable/ic_help"  
  15.           android:title="@string/help" />  
  16. </menu>  
用 MenuInflater.inflate() 去解析XML菜单;

2 制定Option menu
覆盖Activity. onCreateOptionsMenu() 去生成自己的菜单,此方法只在第一次生成options menu时
被调用,对于以后菜单的更改可以在 onPrepareOptionsMenu(Menu) 中完成.

当点击option menuitem 时会触发 onOptionsItemSelected()

3 制定Context menu(具体请参考API Guid)
registerForContextMenu() and pass it the View;
Implement the onCreateContextMenu() method in your Activity;
Implement onContextItemSelected().

4 制定 Popup Menu(API11 才有)

5 Create Menu Group(看API Guide)

6 Using checkable menu

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <menu xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <group android:checkableBehavior="single">  
  4.         <item android:id="@+id/red"  
  5.               android:title="@string/red" />  
  6.         <item android:id="@+id/blue"  
  7.               android:title="@string/blue" />  
  8.     </group>  
  9. </menu>  
single
    Only one item from the group can be checked (radio buttons)
all
    All items can be checked (checkboxes)
none
    No items are checkable 
另外当某个菜单项被按下时你必须自己改变其check状态,系统不会自动改变,就像:

[java]  view plain copy
  1. @Override  
  2. public boolean onOptionsItemSelected(MenuItem item) {  
  3.     switch (item.getItemId()) {  
  4.         case R.id.vibrate:  
  5.         case R.id.dont_vibrate:  
  6.             //改变这些menu item的状态  
  7.             if (item.isChecked()) item.setChecked(false);  
  8.             else item.setChecked(true);  
  9.             return true;  
  10.         default:  
  11.             return super.onOptionsItemSelected(item);  
  12.     }  
  13. }  
三、Dialogs
               <-- AlertDialog
              <-- ProgressDialog
Dialog  <-- DatePickerDialog
              <-- TimePickerDialog

A dialog is always created and displayed as a part of an Activity.
一般情况下你会调用 Activity.onCreateDialog(int) 方法创建Dialog,这时Android System会管理
Dialog的状态并把此Dialog的拥有者设为此Activity.
Activity.onCreateDialog(int) --> (只在第一次创建Dialog时被调用)
Activity.onPrepareDialog(int) (显示前设置Dialog属性)--> Activity.showDialog(int) -->
Activity.dismissDialog(int)/Dialog.dismiss() (Dialog不在显示但Activity会保存其状态) -->
Activity.removeDialog(int) (Dialog被从Activity中删除,这个Dialog的引用被置null)

创建Dialog的一般步骤为:

[java]  view plain copy
  1. //定义好Dialog ID  
  2. static final int DIALOG_PAUSED_ID = 0;  
  3. static final int DIALOG_GAMEOVER_ID = 1;  
  4. //创建时调用  
  5. protected Dialog onCreateDialog(int id) {  
  6.     Dialog dialog;  
  7.     switch(id) {  
  8.     case DIALOG_PAUSED_ID:  
  9.         // do the work to define the pause Dialog  
  10.         break;  
  11.     case DIALOG_GAMEOVER_ID:  
  12.         // do the work to define the game over Dialog  
  13.         break;  
  14.     default:  
  15.         dialog = null;  
  16.     }  
  17.     return dialog;  
  18. }  
  19. //显示Dialog  
  20. showDialog(DIALOG_PAUSED_ID);  
AlertDialog的创建可以使用其Builder,比较简单,具体可以参考API Guide.

ProgressDialog 包括两种,一种为进度条长度不能确定的 spinning circle,另一种有进度条长度且可以
更新这个进度条(此情况下一般会新建一个更新进度条的Thread),这两种情况都不是很复杂,具体请参看
API Guide.

定制自己的Dialog,可以继承自 Dialog也可以继承自 AlertDialog(这样可以利用它的按钮的相关特征),

具体请参看API Guide.

四、Notifications
1 Toast Notifications
A toast can be created and displayed from an Activity or Service.

2 设置一个 Toast 显示的位置
toast.setGravity(Gravity.TOP|Gravity.LEFT, 0, 0); 或
toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
如果想往右一点就设置第2个参数,如果想往下一点就设置第3个参数,具体请参考Toast API

3 Status Notifications
一般是由background的service发出,要使用 Notification和NotificationManager


一个PendingIntent只是代表一个系统内部的 IIntentSender, PendingIntent本身只是一个符号.

下面是文档中的一个例子,花了一点时间研究了一下,下面做一下注释,以笔记下研究成果.(虽然很小)

[java]  view plain copy
  1. static Intent[] makeMessageIntentStack(Context context, CharSequence from,  
  2.         CharSequence msg) {  
  3.     Intent[] intents = new Intent[4];  
  4.     //查看 Intent.makeRestartActivityTask说明  
  5.     //指向一个 root activity  
  6.     intents[0] = Intent.makeRestartActivityTask(new ComponentName(context,  
  7.             com.example.android.apis.ApiDemos.class));  
  8.   
  9.     // "App"  
  10.     intents[1] = new Intent(context, com.example.android.apis.ApiDemos.class);  
  11.     intents[1].putExtra("com.example.android.apis.Path""App");  
  12.     // "App/Notification"  
  13.     intents[2] = new Intent(context, com.example.android.apis.ApiDemos.class);  
  14.     intents[2].putExtra("com.example.android.apis.Path""App/Notification");  
  15.   
  16.     // Now the activity to display to the user.  Also fill in the data it  
  17.     // should display.  
  18.     intents[3] = new Intent(context, IncomingMessageView.class);  
  19.     intents[3].putExtra(IncomingMessageView.KEY_FROM, from);  
  20.     intents[3].putExtra(IncomingMessageView.KEY_MESSAGE, msg);  
  21.   
  22.     return intents;  
  23. }  
  24.   
  25. /** 
  26.  * The notification is the icon and associated expanded entry in the 
  27.  * status bar. 
  28.  */  
  29. void showAppNotification() {  
  30.     // look up the notification manager service  
  31.     NotificationManager nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);  
  32.   
  33.     // The details of our fake message  
  34.     CharSequence from = "Joe";  
  35.     CharSequence message;  
  36.     switch ((new Random().nextInt()) % 3) {  
  37.         case 0: message = "r u hungry?  i am starved"break;  
  38.         case 1: message = "im nearby u"break;  
  39.         default: message = "kthx. meet u for dinner. cul8r"break;  
  40.     }  
  41.   
  42.     //这种行为很像 startActivity(Intent[] intents)  
  43.     //intents[0] 表示一个root activity  
  44.     //intents[1] 相当于 intents[0].startActivity()  
  45.     //intents[] 的最后一个Intent所关联的Activity是与用户交互的,用户可以使用BACK键  
  46.     //回到intents[top-1]  
  47.     //顺便学习了 Intent.fillIn() 和 PendingIntent.send() 方法  
  48.     //上面两个方法要查看相关文档  
  49.     PendingIntent contentIntent = PendingIntent.getActivities(this0,  
  50.             makeMessageIntentStack(this, from, message), PendingIntent.FLAG_CANCEL_CURRENT);  
  51.   
  52.     // The ticker text, this uses a formatted string so our message could be localized  
  53.     String tickerText = getString(R.string.imcoming_message_ticker_text, message);  
  54.   
  55.     // construct the Notification object.  
  56.     Notification notif = new Notification(R.drawable.stat_sample, tickerText,  
  57.             System.currentTimeMillis());  
  58.   
  59.     // Set the info for the views that show in the notification panel.  
  60.     notif.setLatestEventInfo(this, from, message, contentIntent);  
  61.   
  62.     // We'll have this notification do the default sound, vibration, and led.  
  63.     // Note that if you want any of these behaviors, you should always have  
  64.     // a preference for the user to turn them off.  
  65.     notif.defaults = Notification.DEFAULT_ALL;  
  66.   
  67.     // Note that we use R.layout.incoming_message_panel as the ID for  
  68.     // the notification.  It could be any integer you want, but we use  
  69.     // the convention of using a resource id for a string related to  
  70.     // the notification.  It will always be a unique number within your  
  71.     // application.  
  72.     nm.notify(R.string.imcoming_message_ticker_text, notif);  
  73. }  

Notification.FLAG_AUTO_CANCEL 标记,当用记点击时会自己从"通知栏"消失(加红)

调用setLatestEventInfo() 对已经发出的Notification进行修正,主要是修改其text message

5 定制自己的 Notification (看完 Sytle和Theme再回来看)

五、Sytles and Themes
自己定义一个 style

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!-- 注意resources -->  
  3. <resources>  
  4.     <style name="CodeFont" parent="@android:style/TextAppearance.Medium">  
  5.         <item name="android:layout_width">fill_parent</item>  
  6.         <item name="android:layout_height">wrap_content</item>  
  7.         <item name="android:textColor">#00FF00</item>  
  8.         <item name="android:typeface">monospace</item>  
  9.     </style>  
  10. </resources>  
如何继承自己定义的 style, 当然可以使用 parent 属性,但你也可以这样做:

[html]  view plain copy
  1. <style name="CodeFont.Red">  
  2.         <item name="android:textColor">#FF0000</item>  
  3. </style>  
还可以再继承:

[html]  view plain copy
  1. <style name="CodeFont.Red.Big">  
  2.         <item name="android:textSize">30sp</item>  
  3. </style>  
你只能以这种形式继承自己定义的stye,不能以这种形式继承系统内建的style.

如果一个style中的属性,这个View不支持,它只是把它不支持的属性忽略掉.

注意 View 的XML中可以有一个 style=""@style/MyStyle" 属性,而Activity和Application可以有一个
android:theme="@style/MyStyle" 属性.

如果把一个style应用于一个ViewGroup,则仅仅这个ViewGroup应用这个属性,它的孩子不会应用这个属性.

使用系统自定义的style
<activity android:theme="@android:style/Theme.Dialog">

无论style还是theme都是用<style></style>来定义的,所以平台内建的 style和theme 都可以
在 android.R.style 中找到常量值,如果对这些常量值不太理解可以通过查看 styles.xml/themes.xml
查看源代码以帮助理解.现在的问题是,系统内建的style会用到一些属性,比如 
[html]  view plain copy
  1. <style name="Theme">  
  2.     <item name="colorForeground">@android:color/bright_foreground_dark</item>  
  3.     <item name="colorForegroundInverse">@android:color/bright_foreground_dark_inverse</item>  
  4.     <item name="colorBackground">@android:color/background_dark</item>  
  5.     <item name="colorBackgroundCacheHint">?android:attr/colorBackground</item>   
  6. </style>  
那么我们如何知道会有哪些属性需要定义呢?

对于普通的View 可以查看其 Reference 得到其 相关于 XML attributes,还有一些属性
不是针对某一个View的,而是专门用于Theme类的,如android:windowBackground,我们可以在
R.styleable.Theme中找到(其实这些attr是在attrs.xml中定义的,只不过在Theme大类下)
另外:
For a reference of available style attributes that you can use to define a style 
or theme (e.g., "windowBackground" or "textAppearance"), see R.attr or the respective 
View class for which you are creating a style.

6 定制自己的组件
Fully Customized Components:
首先要设计好自己View的特性,即有哪些字段,如下面这个LabelView,它有两个字段:

[java]  view plain copy
  1. public class LabelView extends View {  
  2.     private String mText;  
  3.     private Paint mPaint;  
  4. }  
然后完成对各字段设置的函数:

[java]  view plain copy
  1. public class LabelView extends View {  
  2.     //第一步:确定自己View的字段  
  3.     private String mText;  
  4.     private Paint mPaint;  
  5.       
  6.     //第二步:设置自己字段的方法  
  7.     public void setText(String text) {  
  8.         mText = text;  
  9.     }  
  10.     public void setTextColor(int color) {  
  11.         mPaint.setColor(color);  
  12.     }  
  13.     public void setTextSize(int size) {  
  14.         mPaint.setTextSize(size);  
  15.     }  
  16. }  
再完成构造函数:

[java]  view plain copy
  1. public class LabelView extends View {  
  2.     //第一步:确定自己View的字段  
  3.     private String mText;  
  4.     private Paint mPaint;  
  5.       
  6.     //第二步:设置自己字段的方法  
  7.     public void setText(String text) {  
  8.         mText = text;  
  9.     }  
  10.     public void setTextColor(int color) {  
  11.         mPaint.setColor(color);  
  12.     }  
  13.     public void setTextSize(int size) {  
  14.         mPaint.setTextSize(size);  
  15.     }  
  16.       
  17.     //第三步:完成构造函数  
  18.     public LabelView(Context context) {  
  19.         super(context);  
  20.         ...  
  21.     }  
  22.     public LabelView(Context context, AttributeSet attrs) {  
  23.         super(context, attrs);  
  24.         ...  
  25.     }  
  26.       
  27.     //第四步:完成onMearsure()方法  
  28.     @Override  
  29.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  30.         setMeasuredDimension(intint);  
  31.     }  
  32.       
  33.     //第五步:完成onDraw(Canvas)  
  34.     @Override  
  35.     protected void onDraw(Canvas canvas) {  
  36.         super.onDraw(canvas);  
  37.         canvas.drawXXX();  
  38.     }  
  39. }  

下面是一个完整的例子(SDK 自带的例子):

[java]  view plain copy
  1. import android.content.Context;  
  2. import android.content.res.TypedArray;  
  3. import android.graphics.Canvas;  
  4. import android.graphics.Paint;  
  5. import android.util.AttributeSet;  
  6. import android.view.View;  
  7.   
  8. public class LabelView extends View {  
  9.   
  10.     //第一步  
  11.     private String mText;  
  12.     private Paint mPaint;  
  13.     private int mAscent; /*此字段是在写类的过程中添加的,不是原先设计好的*/  
  14.       
  15.     //第二步  
  16.     public void setText(String text) {  
  17.         mText = text;  
  18.         /*  
  19.             在整个View的大小改变时需要调用 
  20.             此方法,调用此方法后会触发 onMeasure() 方法, 
  21.             重新计算和View相关的大小信息 
  22.         */  
  23.         requestLayout();  
  24.         /* 
  25.             当View的任何内容改变时(包括大小/样式/文字颜色)都 
  26.             需要调用此方法,调用此方法后会触发 onDraw() 方法 
  27.         */  
  28.         invalidate();  
  29.     }  
  30.     public void setTextColor(int color) {  
  31.         mPaint.setColor(color);  
  32.         /*只是改变字体颜色,不改变View大小,所以不用调用requestLayout*/  
  33.         invalidate();  
  34.     }  
  35.     public void setTextSize(int size) {  
  36.         mPaint.setTextSize(size);  
  37.         requestLayout();  
  38.         invalidate();  
  39.     }  
  40.     //第三步  
  41.     public LabelView(Context context) {  
  42.         super(context);  
  43.         initLabelView();  
  44.     }  
  45.     public LabelView(Context context, AttributeSet attrs) {  
  46.         super(context, attrs);  
  47.         initLabelView();  
  48.         /* 
  49.             Context.obtainStyledAttributes(AttributeSet set, int[] attrs) 
  50.             对于此方法第一个参数是XML文件中对此View的属性设置; 
  51.             第二个参数是在/res/valus/attrs.xml文件中定义的此文件的属性集合(包含许多属性) 
  52.         */  
  53.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LableView);  
  54.         /* 
  55.             R.styleable.LableView_text是一个int[] attrs的一个下标值 
  56.         */  
  57.         String s = a.getString(R.styleable.LableView_text);  
  58.         if(s != null) {  
  59.             setText(s);  
  60.         }  
  61.         setTextColor(a.getColor(R.styleable.LableView_textColor, 0xFF000000));  
  62.         int textSize = a.getDimensionPixelOffset(R.styleable.LableView_textSize, 0);  
  63.         if(textSize > 0) {  
  64.             setTextSize(textSize);  
  65.         }  
  66.         a.recycle();  
  67.     }  
  68.     private void initLabelView() {  
  69.         mPaint = new Paint();  
  70.         mPaint.setColor(0xFF000000);  
  71.         mPaint.setTextSize(16);  
  72.         /* 使画出来的形状的"边沿"比较光滑 */  
  73.         mPaint.setAntiAlias(true);  
  74.         setPadding(3333);  
  75.     }  
  76.       
  77.     //第四步  
  78.     @Override  
  79.     /* 
  80.         此函数要决定这个View的大小,本View的Container会把widthMeasureSpec参数 
  81.         传入到此函数,注意widthMeasureSpec不是简单的一个整数,它代表了SpecMode/ 
  82.         SpecSize的信息 
  83.     */  
  84.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  85.         setMeasuredDimension(measureWidth(widthMeasureSpec),   
  86.                 measureHeight(heightMeasureSpec));  
  87.     }  
  88.     private int measureWidth(int widthMeasureSpec) {  
  89.         int result = 0;  
  90.         int specMode = MeasureSpec.getMode(widthMeasureSpec);  
  91.         int specSize = MeasureSpec.getSize(widthMeasureSpec);  
  92.         if(MeasureSpec.EXACTLY == specMode) {  
  93.             result = specSize;  
  94.         } else {  
  95.             result = (int)mPaint.measureText(mText) + getPaddingLeft()   
  96.                         + getPaddingRight();  
  97.             if(MeasureSpec.AT_MOST == specMode) {  
  98.                 result = Math.min(result, specSize);  
  99.             }  
  100.         }  
  101.         return result;  
  102.     }  
  103.     private int measureHeight(int heightMeasureSpec) {  
  104.         int result = 0;  
  105.         int specMode = MeasureSpec.getMode(heightMeasureSpec);  
  106.         int specSize = MeasureSpec.getSize(heightMeasureSpec);  
  107.         mAscent = (int)mPaint.ascent();  
  108.           
  109.         if(MeasureSpec.EXACTLY == specMode) {  
  110.             result = specSize;  
  111.         } else {  
  112.             result = -mAscent + (int)mPaint.descent() + getPaddingTop()   
  113.                         + getPaddingBottom();  
  114.             if(MeasureSpec.AT_MOST == specMode) {  
  115.                 result = Math.min(result, specSize);  
  116.             }  
  117.         }  
  118.         return result;  
  119.     }  
  120.       
  121.     //第五步  
  122.     @Override  
  123.     protected void onDraw(Canvas canvas) {  
  124.         super.onDraw(canvas);  
  125.         canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mPaint);  
  126.     }  
  127.   
  128. }  
在 res/values/attrs.xml 中定义的 LabelView的相关 attr:

[html]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <!-- declare-styleable是一个大组,编译为 R.styleable,且R.styleable中常量都为一个数组,数组中的值是 R.attr 中值 -->  
  4.     <!-- attr 为一个小属性,是declare-styleable的子元素,编译为 R.attrs -->  
  5.     <declare-styleable name="LableView">  
  6.         <attr name="text" format="string" />  
  7.         <attr name="textColor" format="color"/>  
  8.         <attr name="textSize" format="dimension"/>  
  9.     </declare-styleable>  
  10. </resources>  

编译后的 R 文件为:

[java]  view plain copy
  1. public static final class attr {  
  2.     public static final int text=0x7f010000;  
  3.     public static final int textColor=0x7f010001;  
  4.     public static final int textSize=0x7f010002;  
  5. }  
[java]  view plain copy
  1. public static final class styleable {  
  2.     public static final int[] LableView = {  
  3.         0x7f0100000x7f0100010x7f010002  
  4.     };  
  5.   
  6.     //数组的下标,方便在代码中使用,工具自动生成  
  7.     public static final int LableView_text = 0;   
  8.     public static final int LableView_textColor = 1;  
  9.     public static final int LableView_textSize = 2;  
  10. };  
相关文章
|
3月前
|
编译器 API Android开发
Android经典实战之Kotlin Multiplatform 中,如何处理不同平台的 API 调用
本文介绍Kotlin Multiplatform (KMP) 中使用 `expect` 和 `actual` 关键字处理多平台API调用的方法。通过共通代码集定义预期API,各平台提供具体实现,编译器确保正确匹配,支持依赖注入、枚举类处理等,实现跨平台代码重用与原生性能。附带示例展示如何定义跨平台函数与类。
100 0
|
13天前
|
XML JSON API
Title: Empowering E-commerce with the Product Details Upload API Interface
Title: Empowering E-commerce with the Product Details Upload API Interface
|
1月前
|
Web App开发 安全 程序员
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
多年的互联网寒冬在今年尤为凛冽,坚守安卓开发愈发不易。面对是否转行或学习新技术的迷茫,安卓程序员可从三个方向进阶:1)钻研谷歌新技术,如Kotlin、Flutter、Jetpack等;2)拓展新功能应用,掌握Socket、OpenGL、WebRTC等专业领域技能;3)结合其他行业,如汽车、游戏、安全等,拓宽职业道路。这三个方向各有学习难度和保饭碗指数,助你在安卓开发领域持续成长。
70 1
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
|
29天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
82 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
3月前
|
JavaScript 前端开发 Java
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
IT寒冬使APP开发门槛提升,安卓程序员需转型。选项包括:深化Android开发,跟进Google新技术如Kotlin、Jetpack、Flutter及Compose;研究Android底层框架,掌握AOSP;转型Java后端开发,学习Spring Boot等框架;拓展大前端技能,掌握JavaScript、Node.js、Vue.js及特定框架如微信小程序、HarmonyOS;或转向C/C++底层开发,通过音视频项目如FFmpeg积累经验。每条路径都有相应的书籍和技术栈推荐,助你顺利过渡。
63 3
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
|
2月前
|
JSON API 开发者
小红书 API 接口使用指南:笔记详情数据接口的接入与使用
小红书是一款广受喜爱的生活方式分享社交平台,涵盖旅行、美食等领域。其API允许开发者批量获取笔记内容、图片链接及用户互动数据,助力内容分析与营销策略优化。要使用API,需先注册开发者账号并通过认证获取密钥;随后依据官方文档构建与发送HTTP请求,最后处理JSON格式响应数据。整个过程中,请务必遵循平台使用条款,尊重用户隐私权。
|
3月前
|
存储 Linux API
Linux源码阅读笔记08-进程调度API系统调用案例分析
Linux源码阅读笔记08-进程调度API系统调用案例分析
|
3月前
|
Linux API
Linux源码阅读笔记07-进程管理4大常用API函数
Linux源码阅读笔记07-进程管理4大常用API函数
|
3月前
|
JSON Java API
Integrating the 1688 Product Details API Interface for Taobao
The 1688 platform, a subsidiary of Alibaba Group, is a leading wholesale marketplace in China. It provides a vast selection of products from various suppliers, enabling businesses to source goods efficiently. One of the key features that enhance the user experience on 1688 is the ability to access d
|
3月前
|
编解码 安全 Ubuntu
Android Selinux 问题处理笔记
这篇文章是关于处理Android系统中SELinux权限问题的笔记,介绍了如何通过分析SELinux拒绝的日志、修改SELinux策略文件,并重新编译部署来解决权限问题,同时提供了一些SELinux的背景知识和实用工具。
75 0

热门文章

最新文章