上下文菜單可以理解成PC端上的右鍵,當(dāng)需要進(jìn)行復(fù)制或粘貼、刪除或重命名時(shí)就可以選定想要操作的對(duì)象點(diǎn)擊右鍵,在彈出菜單中選擇所需的操作。Android提供了長(zhǎng)按被操作對(duì)象,彈出浮動(dòng)的操作菜單的交互方式,這個(gè)彈出菜單就被稱(chēng)為上下文菜單,任何控件都可以注冊(cè)上下文菜單,采用的有EditText彈出上下文菜單,進(jìn)行清空或粘貼的操作、ListView子Item的刪除和添加等。
設(shè)置一個(gè)上下文菜單一般分為三個(gè)步驟:
創(chuàng)建上下文菜單:覆寫(xiě)onCreateContenxtMenu方法,由其參數(shù)ContextMenu類(lèi)的menu對(duì)象結(jié)合其add方法,添加子菜單。
添加單項(xiàng)選擇監(jiān)聽(tīng):覆寫(xiě)onContextItemSelected方法,由其參數(shù)MenuItem類(lèi)的item對(duì)象結(jié)合其getItemId方法,判斷選擇了哪一個(gè)子菜單。
public class MainActivity extends AppCompatActivity {
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
editText = new EditText(this);
editText.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
editText.setHint("上下文菜單測(cè)試");
registerForContextMenu(editText);//為EditText控件添加上下文菜單
linearLayout.addView(editText);
setContentView(linearLayout);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {//創(chuàng)建上下文菜單
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle("上下文菜單");//上下文菜單的標(biāo)題
menu.setHeaderIcon(android.R.drawable.ic_btn_speak_now); //上下文菜單圖標(biāo)
menu.add(Menu.NONE, 1, 1, "粘貼");
menu.add(Menu.NONE, 2, 2, "清空");
}
@Override
public boolean onContextItemSelected(MenuItem item) {//子菜單選擇事件監(jiān)聽(tīng)
switch (item.getItemId()) {//根據(jù)子菜單ID進(jìn)行菜單選擇判斷
case 1:
ClipboardManager copy = (ClipboardManager) MainActivity.this
.getSystemService(Context.CLIPBOARD_SERVICE);
copy.setText("這是粘貼內(nèi)容");//調(diào)用了系統(tǒng)服務(wù)
String text = copy.getText().toString().trim();
editText.setText(text);
break;
case 2:
editText.setText("");
break;
}
return super.onContextItemSelected(item);
}
}
有幾點(diǎn)說(shuō)明:
用到了通過(guò)Java代碼動(dòng)態(tài)構(gòu)建控件,首先初始化一個(gè)LinearLayout作為父布局,然后調(diào)用其setLayoutParams方法設(shè)置父布局的寬度和高度,setLayoutParams方法需要傳入一個(gè)LinearLayout.LayoutParams類(lèi)的對(duì)象,這里通過(guò)new方法實(shí)例化了一個(gè)對(duì)象,傳入寬(ViewGroup.LayoutParams.MATCH_PARENT)和(ViewGroup.LayoutParams.MATCH_PARENT)兩個(gè)參數(shù)。同樣,初始化了一個(gè)EditText對(duì)象,并設(shè)置了其寬和高屬性,最后父布局調(diào)用addView方法,將子控件(EditText)引入。最后,使用setContentView方法傳入父布局(LinearLayout)。
這里要對(duì)EditText控件添加上下文菜單,因此,將其對(duì)象editText作為參數(shù),傳入registerForContextMenu方法。
在創(chuàng)建上下文菜單時(shí),調(diào)用了ContextMenu類(lèi)的setHeaderTitle和setHeadIcon方法為上下文菜單添加標(biāo)題和標(biāo)題圖標(biāo)。同時(shí)通過(guò)調(diào)用ContextMenu類(lèi)的add方法添加了“粘貼”和“清空”兩個(gè)功能按鈕。這里的add方法需要傳入四個(gè)參數(shù),即分組ID、子菜單ID、子菜單順序和子菜單文本。
運(yùn)行實(shí)例如下:
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/20-1.png" alt="這里寫(xiě)圖片描述" /> http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/20-2.png" alt="這里寫(xiě)圖片描述" />
長(zhǎng)按EditText控件彈出上下文菜單,選擇粘貼功能,將剪切板管理類(lèi)設(shè)置的粘貼內(nèi)容粘貼到EditText中,選擇清空功能,則清空EditText控件。 ListView中也經(jīng)常會(huì)使用到上下文菜單,打開(kāi)全中國(guó)最火的APP微信,長(zhǎng)按任一item,彈出上下文菜單如下圖:
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/20-3.png" alt="這里寫(xiě)圖片描述" />
我們可以看出,該上下文菜單提供了三個(gè)功能標(biāo)記未讀、置頂聊天和刪除該聊天,下面通過(guò)一個(gè)實(shí)例Demo看一下如何實(shí)現(xiàn)置頂和刪除子項(xiàng)的功能。 主布局文件代碼(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
主布局文件中僅防止了一個(gè)ListView控件,設(shè)置寬高屬性為match_parent,id為listview。 ListView子布局代碼(item.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="match_parent">
<ImageView
android:id="@+id/img"
android:src="@mipmap/ic_launcher"
android:layout_width="50dp"
android:layout_height="50dp" />
<TextView
android:id="@+id/tv"
android:text="hello"
android:gravity="center"
android:layout_marginLeft="50dp"
android:textSize="28sp"
android:layout_width="wrap_content"
android:layout_height="50dp" />
</LinearLayout>
設(shè)置了一個(gè)ImageView用于圖片顯示,固定寬高為50dp,設(shè)置一個(gè)TextView顯示文本信息,設(shè)置字號(hào)、寬高、文本內(nèi)容等屬性。 bean類(lèi)(Animal.java) 為了方便讀寫(xiě)操作,這里同樣設(shè)置了JavaBean類(lèi):
public class Animal {
public Animal(String animal, int imgId) {
this.animal = animal;
this.imgId = imgId;
}
private String animal;
private int imgId;
public String getAnimal() {
return animal;
}
public void setAnimal(String animal) {
this.animal = animal;
}
public int getImgId() {
return imgId;
}
public void setImgId(int imgId) {
this.imgId = imgId;
}
}
包括兩個(gè)屬性String性的animal-動(dòng)物名和int性的imgId-圖片id,并設(shè)置了構(gòu)造方法。 適配器類(lèi)(AnimalAdapter.java)
public class AnimalAdapter extends BaseAdapter {
private Context context;
private List<Animal> datas;
//構(gòu)造函數(shù)需要傳入兩個(gè)必要的參數(shù):上下文對(duì)象和數(shù)據(jù)源
public AnimalAdapter(Context context,List<Animal> datas) {
this.context=context;
this.datas=datas;
}
//返回子項(xiàng)的個(gè)數(shù)
@Override
public int getCount() {
return datas.size();
}
//返回子項(xiàng)對(duì)應(yīng)的對(duì)象
@Override
public Object getItem(int position) {
return datas.get(position);
}
//返回子項(xiàng)的下標(biāo)
@Override
public long getItemId(int position) {
return position;
}
//返回子項(xiàng)視圖
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Animal animal= (Animal) getItem(position);
View view;
ViewHolder viewHolder;
if(convertView==null){
view = LayoutInflater.from(context).inflate(R.layout.item,null);
viewHolder=new ViewHolder();
viewHolder.animalImage=(ImageView)view.findViewById(R.id.img);
viewHolder.animalName=(TextView)view.findViewById(R.id.tv);
view.setTag(viewHolder);
}else{
view=convertView;
viewHolder= (ViewHolder) view.getTag();
}
viewHolder.animalName.setText(animal.getAnimal());
viewHolder.animalImage.setImageResource(animal.getImgId());
return view;
}
//創(chuàng)建ViewHolder類(lèi)
class ViewHolder{
ImageView animalImage;
TextView animalName;
}
}
構(gòu)造函數(shù)傳入兩個(gè)參數(shù),上下文對(duì)象和數(shù)據(jù)集。同樣覆寫(xiě)了四個(gè)必須覆寫(xiě)的方法,創(chuàng)建了ViewHolder類(lèi)提高ListView性能。 MainActivity類(lèi)(MainActivity.java)
public class MainActivity extends Activity {
private ListView listView;
private SimpleAdapter simpleAdapter;
private List<Map<String, Object>> datas=new ArrayList<Map<String, Object>>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView=(ListView)findViewById(R.id.listview);
initDatas();//初始化數(shù)據(jù)集
//實(shí)例化SimpleAdapter
simpleAdapter=new SimpleAdapter(this,datas,R.layout.item,new String[]{"img","name"},new int[]{R.id.img,R.id.tv}); listView.setAdapter(simpleAdapter);//設(shè)置配置器
registerForContextMenu(listView);//注冊(cè)上下文菜單
}
private void initDatas() {
Map map1=new HashMap();
map1.put("img",R.drawable.fish);
map1.put("name", "小金魚(yú)");
Map map2=new HashMap();
map2.put("img",R.drawable.horse);
map2.put("name", "千里馬");
Map map3=new HashMap();
map3.put("img",R.drawable.mouse);
map3.put("name", "米老鼠");
Map map4=new HashMap();
map4.put("img",R.drawable.panda);
map4.put("name","大國(guó)寶");
datas.add(map1);
datas.add(map2);
datas.add(map3);
datas.add(map4);
}
//覆寫(xiě)生成上下文菜單的方法
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderIcon(android.R.drawable.ic_btn_speak_now);//設(shè)置圖標(biāo),僅作示例
menu.setHeaderTitle("操作選擇");
menu.add(0, 0, 0, "刪除");
menu.add(0,1,1,"置頂");
}
//對(duì)上下文菜單進(jìn)行選擇監(jiān)聽(tīng)
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo adapterContextMenuInfo= (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int index=adapterContextMenuInfo.position;
switch (item.getItemId()){
case 0:
datas.remove(index);
simpleAdapter.notifyDataSetChanged();
break;
case 1:
Map temp=new HashMap();//臨時(shí)對(duì)象
temp=datas.get(index);
datas.remove(index);//注意刪除和添加的順序,顛倒之后會(huì)出現(xiàn)錯(cuò)誤,讀者可以自行測(cè)試,并思考為什么?
datas.add(0,temp);
simpleAdapter.notifyDataSetChanged();
break;
}
return super.onContextItemSelected(item);
}
}
這里覆寫(xiě)了生成上下文菜單的方法onCreateContextMenu和上下文菜單的選擇監(jiān)聽(tīng)事件onContextItemSelected,在menu的add方法中傳入了四個(gè)參數(shù),分別是:組id,菜單id,顯示順序(int型)和菜單標(biāo)題。需要注意的是在上下文監(jiān)聽(tīng)事件的方法中,通過(guò)傳入對(duì)象item的getMenuInfo方法可以獲得AdapterView.AdapterContextMenuInfo對(duì)象,該對(duì)象中有position屬性,記錄了上下文菜單作用的子項(xiàng)位置信息,這個(gè)信息用于刪除對(duì)應(yīng)的子項(xiàng)。刪除后調(diào)用notifyDataSetChanged方法,刷新ListView顯示。
在置頂操作中,首先用一個(gè)臨時(shí)Map集合保存要置頂?shù)膶?duì)象,而后調(diào)用remove方法刪除這個(gè)對(duì)象,然后再調(diào)用add方法,傳入兩個(gè)參數(shù),第一個(gè)參數(shù)是插入位置,這里傳入0表示插入在頭部,第二個(gè)是插入對(duì)象,這里傳入臨時(shí)對(duì)象temp。最后調(diào)用notifyDataSetChanged方法,刷新ListView顯示。
注意不要忘記在onCreate方法中調(diào)用registerForContextMenu方法,參數(shù)傳入要添加上下文菜單的對(duì)象,這里傳入了listView對(duì)象。 運(yùn)行項(xiàng)目實(shí)例:
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/20-4.png" alt="這里寫(xiě)圖片描述" /> http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/20-5.png" alt="這里寫(xiě)圖片描述" />
選擇最后一項(xiàng)長(zhǎng)按彈出上下文菜單,選擇置頂操作,最后一項(xiàng)移動(dòng)到第一項(xiàng)。
http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/20-6.png" alt="這里寫(xiě)圖片描述" /> http://wiki.jikexueyuan.com/project/twenty-four-Scriptures/images/20-7.png" alt="這里寫(xiě)圖片描述" />
選擇最后一項(xiàng)并長(zhǎng)按彈出上下文菜單,選擇刪除操作,則最后一項(xiàng)被刪除。