android自定義控制項
⑴ android中怎樣實現自定義控制項中的組合控制項
public
class
MyView
extends
View{
//
此處省略
構造方法
private
void
onDraw(Canvas
canvas){
//重寫view的onDraw方法,繪制控制項的樣式
//這里你使用canvas來繪制,你布局中使用這個控制項就是你繪制的樣子
}
//然後你可以定義很多自己的一些方法,用來修改控制項的樣式
//假如你自定義的一個
進度條
的話,就要修改進度條值,你就可以自定義方法,讓實現對象來改變進度值,記得修改後調用validate方法更新顯示。(具體函數記不太清了)
}
大概就是這樣實現的自定義控制項,自定義控制項的話優化是很重要的哦,不然性能會很差。
然後你要使用這個控制項的話,在布局中就需要這樣定義,假如這個自定義控制項類是這樣的:
xxx.xxx.MyView。
則使用時:
⑵ android 自定義控制項 屬性怎麼用
自定義屬性設置
public class lei extends RelativeLayout {
private TextView tv1
public lei(Context context) {
super(context);
}
public lei(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.item,this);
tv1 = findViewById(R.id.tv1);
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.lei);
String str1 = (String) array.getText(R.styleable.lei_settitle);
int str2 = array.getColor(R.styleable.lei_setbackgroudcolor,Color.BLACK);
tv1.setText(str1);
tv1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getContext(), "toast", Toast.LENGTH_SHORT).show();
}
});
array.recycle();
}
}
布局控制項
<com.example.administrator.myapplication.lei
android:id="@+id/ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
cs:setbackgroudcolor="#158616"
cs:settitle="這個是標題"
cs:settitletextcolor="#FFFFFF"
cs:settextrcolor="#FFFFFF"
>
</com.example.administrator.myapplication.lei>
屬性設置
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="lei" >
<attr name="setbackgroudcolor" format="color|reference"/>
<attr name="settitle" format="string|reference"/>
<attr name="settextrcolor" format="color"/>
<attr name="settitletextcolor" format="color"/>
</declare-styleable>
</resources>
⑶ 如何系統的學習android自定義各種酷炫控制項
首先,為什麼需要自定義View?
1. 現有的View滿足不了你的需求,也沒有辦法從已有控制項派生一個出來;界面元素需要自己繪制。
2. 現有View可以滿足要求,把它做成自定義View只是為了抽象:為這個自定義View提供若干方法,方便調用著操縱View。通常做法是派生一個已有View,或者結合xml文件直接inflate。
目前常用的基本上是第二種方式,這種方式非常簡單,與通常的View使用方法基本相同,但是作用卻異常強大,擁有了這一層抽象,代碼更加整潔也更容易維護,通過抽取自定義View的公共操作方法也減少了冗餘代碼,雖然簡單,但不可忽視。
大多數人感覺神秘的應該是第一種,自繪控制項,完全自定義;但其實這兩種方式歸根結底全部都是自繪;不信你去看看TextView的源碼。只不過通常情況下系統幫我們繪制好了一些控制項給開發者使用;OK,接下來就是一個問題。
在講述之前我還是啰嗦地重申一下,復用已有View是最最常用也最有效的自定義View方式,必須熟練使用。
其次,如何自定義View?
想一下,一個View給用戶最直觀的感知是什麼?靜止的形態和動態的操作。靜止的形態意思就是一個View呈現到用戶眼裡長成啥樣子?動態操作指的是,用戶與View之間可以有哪些交互?點擊滑動View的不同地方會有什麼反應?
1. 靜態
如果一個自定義View的樣式都沒有辦法繪制出來,那麼後續的交互就是空談了;我們一步步分解這個問題。
1.1 你的自定義View分為哪幾個部分?是所有的部分都需要手動繪制還是只有一部分——找出需要完全自定義的部分,其他的部分用已有View實現。
1.2 你的自定義View的每個部分長成什麼樣,佔用多大空間——結合理論知識View的measure過程,比如match_parent, wrap_content結合父View的laout_params參數最終測量大小是多少?
1.3 你的自定義View每個部分擺放在哪?相對位置如何?——View的layout過程。
1.4 你的自定義View那些完全需要手動繪制的部分是什麼樣,如何繪制?
你得學會操縱Canvas,學會2D繪圖,什麼?你跟我說3D,OpenGL?學會這些再說。
⑷ android 自定義控制項 自定義控制項 區別
你在layout布局的時候使用的什麼Button啊,TextView啊之類的就是系統控制項,自己定義的控制項的話是通過繼承View類來實現的。
java">publicclassMyViewextendsView{
//此處省略構造方法
privatevoidonDraw(Canvascanvas){
//重寫view的onDraw方法,繪制控制項的樣式
//這里你使用canvas來繪制,你布局中使用這個控制項就是你繪制的樣子
}
//然後你可以定義很多自己的一些方法,用來修改控制項的樣式
//假如你自定義的一個進度條的話,就要修改進度條值,你就可以自定義方法,讓實現對象來改變進度值,記得修改後調用validate方法更新顯示。(具體函數記不太清了)
}
大概就是這樣實現的自定義控制項,自定義控制項的話優化是很重要的哦,不然性能會很差。
然後你要使用這個控制項的話,在布局中就需要這樣定義,假如這個自定義控制項類是這樣的:
xxx.xxx.MyView。
則使用時:
<xxx.xxx.MyView
這些地方一樣的設置寬高,id啊雜七雜八的屬性
/>
⑸ Android 自定義控制項開發中 onLayout如何設置裡面控制項的大小(Android 大神請進……)
ViewGroup在onLayout函數中通過調用其children的layout函數來設置子視圖相對與父視圖中的位置,具體位置由函數layout的參數決定,當我們繼承ViewGroup時必須重載onLayout函數(ViewGroup中onLayout是abstract修飾),然而onMeasure並不要求必須重載,因為相對與layout來說,measure過程並不是必須的,具體後面會提到。首先我們來看下View.java中函數layout和onLayout的源碼:
public void layout(int l, int t, int r, int b) {
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
boolean changed = setFrame(l, t, r, b);
if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);
}
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~LAYOUT_REQUIRED;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLayoutChangeListeners != null) {
ArrayList<OnLayoutChangeListener> listenersCopy =
(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
int numListeners = listenersCopy.size();
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
mPrivateFlags &= ~FORCE_LAYOUT;
}
函數layout的主體過程還是很容易理解的,首先通過調用setFrame函數來對4個成員變數(mLeft,mTop,mRight,mBottom)賦值,然後回調onLayout函數,最後回調所有注冊過的listener的onLayoutChange函數。
對於View來說,onLayout只是一個空實現,一般情況下我們也不需要重載該函數:
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
接著我們來看下ViewGroup.java中layout的源碼:
public final void layout(int l, int t, int r, int b) {
if (mTransition == null || !mTransition.isChangingLayout()) {
super.layout(l, t, r, b);
} else {
// record the fact that we noop'd it; request layout when transition finishes
mLayoutSuppressed = true;
}
}
super.layout(l, t, r, b)調用的即是View.java中的layout函數,相比之下ViewGroup增加了LayoutTransition的處理,LayoutTransition是用於處理ViewGroup增加和刪除子視圖的動畫效果,也就是說如果當前ViewGroup未添加LayoutTransition動畫,或者LayoutTransition動畫此刻並未運行,那麼調用super.layout(l, t, r, b),繼而調用到ViewGroup中的onLayout,否則將mLayoutSuppressed設置為true,等待動畫完成時再調用requestLayout()。
上面super.layout(l, t, r, b)會調用到ViewGroup.java中onLayout,其源碼實現如下:
@Override
protected abstract void onLayout(boolean changed,
int l, int t, int r, int b);
和前面View.java中的onLayout實現相比,唯一的差別就是ViewGroup中多了關鍵字abstract的修飾,也就是說ViewGroup類只能用來被繼承,無法實例化,並且其子類必須重載onLayout函數,而重載onLayout的目的就是安排其children在父視圖的具體位置。重載onLayout通常做法就是起一個for循環調用每一個子視圖的layout(l, t, r, b)函數,傳入不同的參數l, t, r, b來確定每個子視圖在父視圖中的顯示位置。
那layout(l, t, r, b)中的4個參數l, t, r, b如何來確定呢?聯想到之前的measure過程,measure過程的最終結果就是確定了每個視圖的mMeasuredWidth和mMeasuredHeight,這兩個參數可以簡單理解為視圖期望在屏幕上顯示的寬和高,而這兩個參數為layout過程提供了一個很重要的依據(但不是必須的),為了說明這個過程,我們來看下LinearLayout的layout過程:
void layoutVertical() {
……
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
if (child == null) {
childTop += measureNullChild(i);
} else if (child.getVisibility() != GONE) {
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
……
setChildFrame(child, childLeft, childTop + getLocationOffset(child),
childWidth, childHeight);
childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
i += getChildrenSkipCount(child, i);
}
}
}
private void setChildFrame(View child, int left, int top, int width, int height) {
child.layout(left, top, left + width, top + height);
}
從setChildFrame可以看到LinearLayout中的子視圖的右邊界等於left + width,下邊界等於top+height,也就是說在LinearLayout中其子視圖顯示的寬和高由measure過程來決定的,因此measure過程的意義就是為layout過程提供視圖顯示範圍的參考值。
layout過程必須要依靠measure計算出來的mMeasuredWidth和mMeasuredHeight來決定視圖的顯示大小嗎?事實並非如此,layout過程中的4個參數l, t, r, b完全可以由視圖設計者任意指定,而最終視圖的布局位置和大小完全由這4個參數決定,measure過程得到的mMeasuredWidth和mMeasuredHeight提供了視圖大小的值,但我們完全可以不使用這兩個值,可見measure過程並不是必須的。\\
說到這里就不得不提getWidth()、getHeight()和getMeasuredWidth()、getMeasuredHeight()這兩對函數之間的區別,getMeasuredWidth()、getMeasuredHeight()返回的是measure過程得到的mMeasuredWidth和mMeasuredHeight的值,而getWidth()和getHeight()返回的是mRight - mLeft和mBottom - mTop的值,看View.java中的源碼便一清二楚了:
public final int getMeasuredWidth() {
return mMeasuredWidth & MEASURED_SIZE_MASK;
}
public final int getWidth() {
return mRight - mLeft;
}
這也解釋了為什麼有些情況下getWidth()和getMeasuredWidth()以及getHeight()和getMeasuredHeight()會得到不同的值。
⑹ Android 自定義控制項 動態設置高度
Android動態改變View控制項大小的方法:
1、聲明控制項參數獲取對象 LayoutParams lp;
2、獲取控制項參數: lp = 控制項id.getLayoutParams();
3、設置控制項參數:如高度。 lp.height -= 10;
4:、使設置生效:控制項id.setLayoutParams(lp);
例如如要把Imageview下移200px: ImageView.setPadding( ImageView.getPaddingLeft(), ImageView.getPaddingTop()+200, ImageView.getPaddingRight(), ImageView.getPaddingBottom());
⑺ android 如何封裝一個自定義的控制項
一般使用繼承就能實現自定義的控制項。android的自定義控制項主要是繼承View或者ViewGroup這2個類及其子類。
控制項是對數據和方法的封裝。控制項可以有自己的屬性和方法。屬性是控制項數據的簡單訪問者。方法則是控制項 的一些簡單而可見的功能。
⑻ android自定義控制項怎麼用
一、控制項自定義屬性介紹
以下示例中代碼均在values/attrs.xml 中定義,屬性均可隨意命名。
1. reference:參考某一資源ID。
示例:
<declare-styleable name = "名稱">
<attr name = "background" format = "reference" />
<attr name = "src" format = "reference" />
</declare-styleable>
2. color:顏色值。
示例:
<declare-styleable name = "名稱">
<attr name = "textColor" format = "color" />
</declare-styleable>
3. boolean:布爾值。
示例:
<declare-styleable name = "名稱">
<attr name = "focusable" format = "boolean" />
</declare-styleable>
4. dimension:尺寸值。
示例:
<declare-styleable name = "名稱">
<attr name = "layout_width" format = "dimension" />
</declare-styleable>
5. float:浮點值。
示例:
<declare-styleable name = "名稱">
<attr name = "fromAlpha" format = "float" />
<attr name = "toAlpha" format = "float" />
</declare-styleable>
6. integer:整型值。
示例:
<declare-styleable name = "名稱">
<attr name = "frameDuration" format="integer" />
<attr name = "framesCount" format="integer" />
</declare-styleable>
7. string:字元串。
示例:
<declare-styleable name = "名稱">
<attr name = "text" format = "string" />
</declare-styleable>
8. fraction:百分數。
示例:
<declare-styleable name="名稱">
<attr name = "pivotX" format = "fraction" />
<attr name = "pivotY" format = "fraction" />
</declare-styleable>
9. enum:枚舉值。
示例:
<declare-styleable name="名稱">
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
</declare-styleable>
10. flag:位或運算。
示例:
<declare-styleable name="名稱">
<attr name="windowSoftInputMode">
<flag name = "stateUnspecified" value = "0" />
<flag name = "stateUnchanged" value = "1" />
<flag name = "stateHidden" value = "2" />
<flag name = "stateAlwaysHidden" value = "3" />
</attr>
</declare-styleable>
11.多類型。
示例:
<declare-styleable name = "名稱">
<attr name = "background" format = "reference|color" />
</declare-styleable>
二、屬性的使用以及自定義控制項的實現
1、構思控制項的組成元素,思考所需自定義的屬性。
比如:我要做一個 <帶陰影的按鈕,按鈕正下方有文字說明>(類似9宮格按鈕)
新建values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="custom_view">
<attr name="custom_id" format="integer" />
<attr name="src" format="reference" />
<attr name="background" format="reference" />
<attr name="text" format="string" />
<attr name="textColor" format="color" />
<attr name="textSize" format="dimension" />
</declare-styleable>
</resources>
以上,所定義為custom_view,custom_id為按鈕id,src為按鈕,background為陰影背景,text為按鈕說明,textColor為字體顏色,textSize為字體大小。
2、怎麼自定義控制項呢,怎麼使用這些屬性呢?話不多說請看代碼,CustomView :
package com.nanlus.custom;
import com.nanlus.custom.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
public class CustomView extends FrameLayout implements OnClickListener {
private CustomListener customListener = null;
private Drawable mSrc = null, mBackground = null;
private String mText = "";
private int mTextColor = 0;
private float mTextSize = 20;
private int mCustomId = 0;
private ImageView mBackgroundView = null;
private ImageButton mButtonView = null;
private TextView mTextView = null;
private LayoutParams mParams = null;
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.custom_view);
mSrc = a.getDrawable(R.styleable.custom_view_src);
mBackground = a.getDrawable(R.styleable.custom_view_background);
mText = a.getString(R.styleable.custom_view_text);
mTextColor = a.getColor(R.styleable.custom_view_textColor,
Color.WHITE);
mTextSize = a.getDimension(R.styleable.custom_view_textSize, 20);
mCustomId = a.getInt(R.styleable.custom_view_custom_id, 0);
mTextView = new TextView(context);
mTextView.setTextSize(mTextSize);
mTextView.setTextColor(mTextColor);
mTextView.setText(mText);
mTextView.setGravity(Gravity.CENTER);
mTextView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
mButtonView = new ImageButton(context);
mButtonView.setImageDrawable(mSrc);
mButtonView.setBackgroundDrawable(null);
mButtonView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
mButtonView.setOnClickListener(this);
mBackgroundView = new ImageView(context);
mBackgroundView.setImageDrawable(mBackground);
mBackgroundView.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
addView(mBackgroundView);
addView(mButtonView);
addView(mTextView);
this.setOnClickListener(this);
a.recycle();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParams = (LayoutParams) mButtonView.getLayoutParams();
if (mParams != null) {
mParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
mButtonView.setLayoutParams(mParams);
}
mParams = (LayoutParams) mBackgroundView.getLayoutParams();
if (mParams != null) {
mParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
mBackgroundView.setLayoutParams(mParams);
}
mParams = (LayoutParams) mTextView.getLayoutParams();
if (mParams != null) {
mParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
mTextView.setLayoutParams(mParams);
}
}
public void setCustomListener(CustomListener l) {
customListener = l;
}
@Override
public void onClick(View v) {
if (customListener != null) {
customListener.onCuscomClick(v, mCustomId);
}
}
public interface CustomListener {
void onCuscomClick(View v, int custom_id);
}
}
代碼很簡單,就不多說,下面來看看我們的CustomView是怎麼用的,請看:
3、自定義控制項的使用
話不多說,請看代碼,main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:nanlus="http://schemas.android.com/apk/res/com.nanlus.custom"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:orientation="horizontal" >
<com.nanlus.custom.CustomView
android:id="@+id/custom1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
nanlus:background="@drawable/background"
nanlus:custom_id="1"
nanlus:src="@drawable/style_button"
nanlus:text="按鈕1" >
</com.nanlus.custom.CustomView>
</LinearLayout>
</RelativeLayout>
在這里需要解釋一下,
xmlns:nanlus="http://schemas.android.com/apk/res/com.nanlus.custom"
nanlus為在xml中的前綴,com.nanlus.custom為包名
4、在Activity中,直接上代碼
package com.nanlus.custom;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.nanlus.BaseActivity;
import com.nanlus.custom.R;
import com.nanlus.custom.CustomView.CustomListener;
public class CustomActivity extends BaseActivity implements CustomListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((CustomView) this.findViewById(R.id.custom1)).setCustomListener(this);
}
@Override
public void onCuscomClick(View v, int custom_id) {
switch (custom_id) {
case 1:
Toast.makeText(this, "hello !!!", Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
}
⑼ android 自定義ui控制項有哪些
布局(Layout)的概念是針對Activity的,Activity就是布滿整 個Android設備的窗口或者懸浮於其他窗口上的交互界面。在一個應用程序中通常由多個Activity構成,每個需要顯示的Activity都需要在AndroidManifest.xml文件之中聲明。
通常情況下,開發人員可以使用兩種方式來創建UI組件,一種方式是使用XML方式來配置UI組件的相關屬性,然後裝載這些UI組件,這也是最常用的方式。但是有些特殊情況下,需要動態生成UI組件,則需要使用第二種方式,完全使用Java代碼來創建UI組件。
XML布局文件是Android系統中定義的Layout的常用方式,所有布局文件必須包含在res/layout目錄中,且必須符合Java的命名 規范。當在res/layout目錄下新增了布局文件之後,R.java文件會自動收錄該布局資源,Java代碼可通過setContentView方法 在Activity中顯示該Layout。
setContentView(R.layout.<資源名稱>);
在布局文件中可以指定UI組件的android:id屬性,該屬性的屬性值代表該組件的唯一標識。通過Activity.findViewById()訪問,並且findViewById()必須在setContentView載入xml文件之後使用,否則會拋出異常。
findViewById(R.id.)
Android應用的絕大部分UI組件都放在android.widget包及其子包、android.view包及其子包中,Android應用的 所有UI組件都繼承了View類。View類還有一個重要的子類:ViewGroup,ViewGroup類是所有布局管理器的父類。
ViewGroup容器控制其子組件的分布依賴於ViewGroup.LayoutParams、ViewGroup.MarginLayoutParams兩個內部類。
ViewGroup.LayoutParams提供兩個XML屬性設定組件的大小。
android:layout_height:指定該子組件的基本高度;
android:layout_width:指定該子組件的基本寬度。
這兩個屬性有三個基本值,這兩個屬性有三個特定的值:
fill_parent:指定組件的高度、寬度與父容器組件的一樣。
match_parent:與fill_parent一樣,Android2.2開始推薦使用。
warp_content:內容包裹。
ViewGroup.MarginLayoutParams用於控制子組件周圍的頁邊距。
android:layout_marginBottom(下邊距);
android:layout_marginLeft(左邊距);
android:layout_marginRight(右邊距):
layout_marginTop(上邊距)
對於View的尺寸,android提供了三種單位供選擇使用:
px:像素。
dp:dpi,表示屏幕實際的像素。
sp:與scale無關的像素,與dp類似。
尺寸單位選擇的技巧:如果設置長度、高度等屬性時可以使用dp或sp,但是如果設置字體,需要使用px。如果使用dp或sp,系統會根據屏幕密度的變化進行轉換。
為了適應各種界面風格,Android提供了五種布局規范,利用這五種布局,基本上可以在設備上隨心所欲的擺放任何UI組件,這五種布局分別是:
FrameLayout(幀布局)。
LinearLayout(線性布局)
RelativeLayout(相對布局)。
TableLayout(表格布局)。
AbsoluteLayout(絕對布局)。
線性布局(LinearLayout)
LinearLayout是最常用的布局方式,在XML文件中使用標記。它會將容器里的UI組件一個一個挨著排列起來。但是LinearLayout不會換行,當UI組件超出屏幕之後,則不會被顯示出來。LinearLayout有兩個重要的XML屬性:androidgravity(對齊方 式);android:orientation(排列方式)。
android:orientation(排列方式),設定了LinearLayout中包含的UI組件的排列方式,有兩個選項vertical(豎向)、horizontal(橫向,默認值)
android:gravity(對齊方式),設定LinearLayout中包含UI組件的對齊方式,其選項很多,常用上(top)、下(bottom)、左(left)、右(right)。