Android高手進(jìn)階教程(二十六)之---Android超仿Path菜單的功能實(shí)現(xiàn)!
Hi~大家好,出來創(chuàng)業(yè)快3個(gè)月了,一切還不錯(cuò),前一段時(shí)間用了業(yè)余時(shí)間搞了個(gè)問答類網(wǎng)站YQMA.想做中國的stackoverflow,哈哈,只是YY下,希望大家多多支持!
好了,今天給大家分享的是Path菜單的簡單實(shí)現(xiàn),可以支持自定義方向(左上,右上,右下,左下),并且可以自定義菜單的個(gè)數(shù),難點(diǎn)就是菜單的擺放位置(動(dòng)態(tài)設(shè)置margin),還有動(dòng)畫的實(shí)現(xiàn),其實(shí)動(dòng)畫只是簡單用了個(gè)TranslateAnimation,N個(gè)菜單一起移動(dòng)的時(shí)候感覺很cool~
這里也用到了自定義標(biāo)簽,這里不懂的童鞋可以看我 Android高手進(jìn)階教程(四)之----Android 中自定義屬性(attr.xml,TypedArray)的使用! 這篇文章.好了廢話不多說了,
首先創(chuàng)建一個(gè)android工程命名為PathTest.目錄結(jié)構(gòu)如下圖:
第二步:在values文件夾下新建一個(gè)attrs.xml文件,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="PathMenuView">
<attr name="position">
<enum name="left_top" value="0"></enum>
<enum name="right_top" value="1"></enum>
<enum name="right_bottom" value="2"></enum>
<enum name="left_bottom" value="3"></enum>
</attr>
</declare-styleable>
</resources>
第三步:新建一個(gè)PathMenuView.Java這個(gè)就是我們自定義的Path菜單控件,代碼如下:
package com.tutor.path;
import androidcontentContext;
import androidcontentresTypedArray;
import androidutilAttributeSet;
import androidviewGravity;
import androidviewView;
import androidviewViewGroup;
import androidviewanimationAnimation;
import androidviewanimationAnticipateInterpolator;
import androidviewanimationOvershootInterpolator;
import androidviewanimationTranslateAnimation;
import androidwidgetFrameLayout;
import androidwidgetImageView;
/**
* @author frankiewei
* 超級仿path菜單
* position定義菜單的位置,目前支持:左上;右上;右下;左下四個(gè)方向。
* menuResIds定義出現(xiàn)的菜單的資源ID
*/
public class PathMenuView extends FrameLayout {
private static final int LEFT_TOP = 0;
private static final int RIGHT_TOP = 1;
private static final int RIGHT_BOTTOM = 2;
private static final int LEFT_BOTTOM = 3;
/**
* 默認(rèn)的位置是在右下角
*/
private int position = 3;
/**
* 那個(gè)圓形菜單
*/
private ImageView mHome;
/**
* 上下文
*/
private Context mContext;
/**
* 設(shè)備的寬度
*/
private int mWIDTH = 0;
/**
* 設(shè)備的高度
*/
private int mHEIGHT = 0;
/**
* 設(shè)備的density
*/
private float mDensity;
/**
* 菜單是否顯示
*/
private boolean bMenuShow;
private static int xOffset = 15;
private static int yOffset = -13;
/**
* 菜單的資源個(gè)數(shù)
*/
private int[] menuResIds = {Rdrawablecomposer_camera,Rdrawablecomposer_music,
Rdrawablecomposer_sleep,Rdrawablecomposer_music,Rdrawablecomposer_place};
public PathMenuView(Context context){
super(context);
setupViews();
}
public PathMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = contextobtainStyledAttributes(attrs,
RstyleablePathMenuView);
position = agetInt(RstyleablePathMenuView_position,3);
arecycle();
setupViews();
}
private void setupViews(){
mContext = getContext();
mHEIGHT = mContextgetResources()getDisplayMetrics()heightPixels;
mWIDTH = mContextgetResources()getDisplayMetrics()widthPixels;
mDensity = mContextgetResources()getDisplayMetrics()density;
xOffset = (int) (667 * mDensity);
yOffset = (int) (667 * mDensity);
mHome = new ImageView(mContext);
mHomesetImageResource(Rdrawablecomposer_button);
mHomesetOnClickListener(listener);
addView(mHome);
LayoutParams mHomeparams = (FrameLayoutLayoutParams)mHomegetLayoutParams();
mHomeparamswidth = LayoutParamsWRAP_CONTENT;
mHomeparamsheight = LayoutParamsWRAP_CONTENT;
switch (position) {
case LEFT_TOP:
mHomeparamsgravity = GravityLEFT | GravityTOP;
for (int i = 0; i < menuResIdslength; i++) {
int width_padding = mWIDTH / ((menuResIdslength - 1) * 2);
int height_padding = mHEIGHT / ((menuResIdslength - 1) * 2);
ImageView imageView = new ImageView(mContext);
imageViewsetImageResource(menuResIds[i]);
addView(imageView);
LayoutParams params = (FrameLayoutLayoutParams) imageView
getLayoutParams();
paramswidth = LayoutParamsWRAP_CONTENT;
paramsheight = LayoutParamsWRAP_CONTENT;
paramsleftMargin = mWIDTH / 2
- ((menuResIdslength - i - 1) * width_padding);
paramstopMargin = mHEIGHT / 2 - i * height_padding;
paramsgravity = GravityLEFT | GravityTOP;
imageViewsetLayoutParams(params);
}
break;
case RIGHT_TOP:
mHomeparamsgravity = GravityRIGHT | GravityTOP;
for (int i = 0; i < menuResIdslength; i++) {
int width_padding = mWIDTH / ((menuResIdslength - 1) * 2);
int height_padding = mHEIGHT / ((menuResIdslength - 1) * 2);
ImageView imageView = new ImageView(mContext);
imageViewsetImageResource(menuResIds[i]);
addView(imageView);
LayoutParams params = (FrameLayoutLayoutParams) imageView
getLayoutParams();
paramswidth = LayoutParamsWRAP_CONTENT;
paramsheight = LayoutParamsWRAP_CONTENT;
paramsrightMargin = mWIDTH / 2
- ((menuResIdslength - i - 1) * width_padding);
paramstopMargin = mHEIGHT / 2 - i * height_padding;
paramsgravity = GravityRIGHT | GravityTOP;
imageViewsetLayoutParams(params);
}
break;
case RIGHT_BOTTOM:
mHomeparamsgravity = GravityRIGHT | GravityBOTTOM;
for (int i = 0; i < menuResIdslength; i++) {
int width_padding = mWIDTH / ((menuResIdslength - 1) * 2);
int height_padding = mHEIGHT / ((menuResIdslength - 1) * 2);
ImageView imageView = new ImageView(mContext);
imageViewsetImageResource(menuResIds[i]);
addView(imageView);
LayoutParams params = (FrameLayoutLayoutParams) imageView
getLayoutParams();
paramswidth = LayoutParamsWRAP_CONTENT;
paramsheight = LayoutParamsWRAP_CONTENT;
paramsrightMargin = mWIDTH / 2
- ((menuResIdslength - i - 1) * width_padding);
paramsbottomMargin = mHEIGHT / 2 - i * height_padding;
paramsgravity = GravityRIGHT | GravityBOTTOM;
imageViewsetLayoutParams(params);
}
break;
case LEFT_BOTTOM:
mHomeparamsgravity = GravityLEFT | GravityBOTTOM;
for(int i = 0; i < menuResIdslength; i++){
int width_padding = mWIDTH / ((menuResIdslength - 1) * 2);
int height_padding = mHEIGHT / ((menuResIdslength -1) * 2);
ImageView imageView = new ImageView(mContext);
imageViewsetImageResource(menuResIds[i]);
addView(imageView);
LayoutParams params = (FrameLayoutLayoutParams)imageViewgetLayoutParams();
paramswidth = LayoutParamsWRAP_CONTENT;
paramsheight = LayoutParamsWRAP_CONTENT;
paramsleftMargin = mWIDTH / 2 - ((menuResIdslength - i - 1) * width_padding);
paramsbottomMargin = mHEIGHT / 2 - i * height_padding;
paramsgravity = GravityLEFT | GravityBOTTOM;
imageViewsetLayoutParams(params);
}
break;
default:
break;
}
mHomesetLayoutParams(mHomeparams);
}
private OnClickListener listener = new OnClickListener() {
public void onClick(View v) {
if (!bMenuShow) {
startAnimationIn(PathMenuViewthis, 300);
} else {
startAnimationOut(PathMenuViewthis, 300);
}
bMenuShow = !bMenuShow;
}
};
/**
* 菜單隱藏動(dòng)畫
*
* @param group
* @param duration
*/
private void startAnimationIn(ViewGroup group, int duration) {
for (int i = 1; i < groupgetChildCount(); i++) {
ImageView imageview = (ImageView) groupgetChildAt(i);
imageviewsetVisibility(0);
MarginLayoutParams mlp = (MarginLayoutParams) imageview
getLayoutParams();
Animation animation = null;
switch (position) {
case LEFT_TOP:
animation = new TranslateAnimation(0F,-mlpleftMargin+xOffset,0F,-mlptopMargin + yOffset);
break;
case RIGHT_TOP:
animation = new TranslateAnimation(mlprightMargin - xOffset,0F,-mlptopMargin + yOffset,0F);
break;
case LEFT_BOTTOM:
animation = new TranslateAnimation(0F, -mlpleftMargin+ xOffset, 0F, -yOffset + mlpbottomMargin);
break;
case RIGHT_BOTTOM:
animation = new TranslateAnimation(mlprightMargin-xOffset,0F,-yOffset + mlpbottomMargin, 0F);
break;
default:
break;
}
animationsetFillAfter(true);
animationsetDuration(duration);
animationsetStartOffset((i * 100) / (-1 + groupgetChildCount()));
animationsetInterpolator(new OvershootInterpolator(2F));
imageviewstartAnimation(animation);
}
}
/**
* 菜單顯示動(dòng)畫
*
* @param group
* @param duration
*/
private void startAnimationOut(ViewGroup group,int duration){
for (int i = 1; i < groupgetChildCount(); i++) {
final ImageView imageview = (ImageView) group
getChildAt(i);
MarginLayoutParams mlp = (MarginLayoutParams) imageviewgetLayoutParams();
Animation animation = null;
switch (position) {
case LEFT_TOP:
animation = new TranslateAnimation(-mlpleftMargin+xOffset,0F,-mlptopMargin + yOffset,0F);
break;
case RIGHT_TOP:
animation = new TranslateAnimation(0F,mlprightMargin - xOffset,0F,-mlptopMargin + yOffset);
break;
case LEFT_BOTTOM:
animation = new TranslateAnimation(-mlpleftMargin+xOffset,0F, -yOffset + mlpbottomMargin,0F);
break;
case RIGHT_BOTTOM:
animation = new TranslateAnimation(0F,mlprightMargin-xOffset, 0F,-yOffset + mlpbottomMargin);
break;
default:
break;
}
animationsetFillAfter(true);animationsetDuration(duration);
animationsetStartOffset(((groupgetChildCount()-i) * 100)
/ (-1 + groupgetChildCount()));
animationsetInterpolator(new AnticipateInterpolator(2F));
imageviewstartAnimation(animation);
}
}
}
第四步:PathTestActivity.java以及用到的布局文件main.xml代碼如下:
PathTestActivity.java(基本沒修改代碼)代碼如下:
package comtutorpath;
import androidappActivity;
import androidosBundle;
public class PathTestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
superonCreate(savedInstanceState);
setContentView(Rlayoutmain);
}
}
main.xml代碼如下:
<?xml version="0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemasandroidcom/apk/res/android"
xmlns:tutor="http://schemasandroidcom/apk/res/comtutorpath"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<comtutorpathPathMenuView
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tutor:position="right_bottom"
/>
</LinearLayout>
運(yùn)行點(diǎn)擊效果如下:

圖1:默認(rèn)是在右下方這里menuResIds定義了五個(gè)菜單

圖2:點(diǎn)擊紅色菜單,菜單收回.
下面我們修改main.xml的tutor屬性為left_bottom,并且修改PathMenuView.java中的menuResIds.
tutor:position="left_bottom"
效果如下:

圖3:自定義在左下角,六個(gè)菜單。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中定時(shí)執(zhí)行任務(wù)的3種實(shí)現(xiàn)方法(推薦)
下面小編就為大家?guī)硪黄狝ndroid中定時(shí)執(zhí)行任務(wù)的3種實(shí)現(xiàn)方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11
Activity跳轉(zhuǎn)時(shí)生命周期跟蹤的實(shí)例
下面小編就為大家?guī)硪黄狝ctivity跳轉(zhuǎn)時(shí)生命周期跟蹤的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03
老生常談Android HapticFeedback(震動(dòng)反饋)
下面小編就為大家?guī)硪黄仙U凙ndroid HapticFeedback(震動(dòng)反饋)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04
Android HttpURLConnection.getResponseCode()錯(cuò)誤解決方法
在使用HttpURLConnection.getResponseCode()的時(shí)候直接報(bào)錯(cuò)是IOException錯(cuò)誤,一直想不明白,同一個(gè)程序我調(diào)用了兩次,結(jié)果有一個(gè)鏈接一直O(jiān)K,另一個(gè)卻一直報(bào)這個(gè)錯(cuò)誤2013-06-06
Android開發(fā)快速實(shí)現(xiàn)底部導(dǎo)航欄示例
這篇文章主要為大家介紹了Android開發(fā)快速實(shí)現(xiàn)底部導(dǎo)航欄的示例代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
android編程實(shí)現(xiàn)系統(tǒng)圖片剪裁的方法
這篇文章主要介紹了android編程實(shí)現(xiàn)系統(tǒng)圖片剪裁的方法,涉及Android針對圖片的獲取、修改、保存等操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
詳解Flutter如何繪制曲線,折線圖及波浪動(dòng)效
這篇文章主要為大家介紹線條類圖形的繪制(正弦曲線、折線圖),并且結(jié)合 Animation 實(shí)現(xiàn)了常見的波浪動(dòng)效,感興趣的小伙伴可以了解一下2022-03-03
Android實(shí)現(xiàn)微信朋友圈發(fā)本地視頻功能
這篇文章主要介紹了Android實(shí)現(xiàn)微信朋友圈發(fā)本地視頻功能的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11

