我想在我的应用中开发this rotation。我已经实现了“向下”菜单(“můjdeporter”,“moje Volvo”,“kontakty”),我需要实现“上部”旋转菜单。
我该怎么办?你有提示吗?希望你了解我。
图片(请在链接中观看上面的视频):
Menu_item_test.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" >
<ImageView
android:id="@+id/menuItemImg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/tab_1_1" />
</RelativeLayout>
activity_main.xml中:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/rotationMenu" >
</FrameLayout>
<ImageView
android:id="@+id/imageViewShadow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="60dp"
android:contentDescription="shadow"
android:scaleType="fitXY"
android:src="@drawable/half_round_back" />
<cz.mixedapps.volvista.RotationMenu
android:id="@+id/rotationMenu"
android:layout_width="match_parent"
android:layout_height="265dp"
android:layout_alignParentBottom="true" >
</cz.mixedapps.volvista.RotationMenu>
</RelativeLayout>
答案 0 :(得分:4)
我已经整理了一个复制行为的自定义视图,你仍然需要像你的例子那样设置样式,但它适用于任意数量的子视图,目前看起来像这样:
编辑:我添加了使用showRotationMenu()
和hideRotationMenu()
两种方法显示和隐藏上方旋转菜单的功能:
当然,您可以做很多事情来改善这种观点。我只是在15分钟内写下了这个,因此边缘有点粗糙。但它应该足以让你走上正轨。按钮的外观和旋转的视图都可以完全自定义。
RotationMenu.java:
import android.content.Context;
import android.content.res.Resources;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.*;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
/**
* Created by Xaver Kapeller on 26/03/14.
*/
public class RotationMenu extends LinearLayout {
private final DataSetObserver dataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
reloadAdapter();
}
};
private RotationMenuAdapter adapter;
private FrameLayout flViewContainer;
private LinearLayout llMenu;
private View currentView;
private View previousView;
private int animationPivotX;
private int animationPivotY;
private int selectedPosition = 0;
public RotationMenu(Context context) {
super(context);
setupMenu();
}
public RotationMenu(Context context, AttributeSet attrs) {
super(context, attrs);
setupMenu();
}
public RotationMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setupMenu();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
this.animationPivotX = w / 2;
this.animationPivotY = h;
}
private void setupMenu() {
this.setOrientation(VERTICAL);
this.flViewContainer = new FrameLayout(getContext());
this.addView(this.flViewContainer, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpToPixel(150)));
this.llMenu = new LinearLayout(getContext());
this.llMenu.setOrientation(LinearLayout.HORIZONTAL);
this.addView(this.llMenu, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
private int dpToPixel(int dp) {
float scale = getDisplayDensityFactor();
return (int) (dp * scale + 0.5f);
}
private float getDisplayDensityFactor() {
Resources res = getResources();
if (res != null) {
DisplayMetrics metrics = res.getDisplayMetrics();
if(metrics != null) {
return metrics.density;
}
}
return 1.0f;
}
public RotationMenuAdapter getAdapter() {
return this.adapter;
}
public void setAdapter(RotationMenuAdapter adapter) {
if (adapter != null) {
if (this.adapter != null) {
this.adapter.unregisterDataSetObserver(this.dataSetObserver);
}
adapter.registerDataSetObserver(this.dataSetObserver);
this.adapter = adapter;
reloadAdapter();
}
}
public boolean isRotationMenuVisible() {
return this.flViewContainer.getVisibility() == View.VISIBLE;
}
public void showRotationMenu() {
if(this.flViewContainer.getVisibility() != View.VISIBLE) {
this.flViewContainer.setVisibility(View.VISIBLE);
AnimationSet set = new AnimationSet(false);
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0);
translateAnimation.setDuration(1000);
set.addAnimation(translateAnimation);
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(1000);
set.addAnimation(alphaAnimation);
this.flViewContainer.startAnimation(set);
}
}
public void hideRotationMenu() {
if(this.flViewContainer.getVisibility() == View.VISIBLE) {
AnimationSet set = new AnimationSet(false);
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1);
translateAnimation.setDuration(1000);
set.addAnimation(translateAnimation);
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
alphaAnimation.setDuration(1000);
set.addAnimation(alphaAnimation);
set.setAnimationListener(new ViewAnimationEndListener(this.flViewContainer) {
@Override
protected void onAnimationEnd(Animation animation, View view) {
view.setVisibility(View.GONE);
}
});
this.flViewContainer.startAnimation(set);
}
}
private void reloadAdapter() {
Context context = getContext();
if (this.adapter != null && context != null) {
int viewCount = this.adapter.getCount();
int oldViewCount = this.llMenu.getChildCount();
for (int i = 0; i < Math.max(oldViewCount, viewCount); i++) {
if (i < viewCount) {
LayoutParams layoutParams = new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
View menuItem;
if (i < this.llMenu.getChildCount()) {
menuItem = this.adapter.getMenuItemView(i, this.llMenu.getChildAt(i), this.llMenu);
if(menuItem.getParent() == null) {
this.llMenu.removeViewAt(i);
this.llMenu.addView(menuItem, i, layoutParams);
}
} else {
menuItem = this.adapter.getMenuItemView(i, null, this.llMenu);
this.llMenu.addView(menuItem, layoutParams);
}
menuItem.setOnClickListener(new MenuItemClickListener(i));
} else {
this.llMenu.removeViewAt(i);
}
}
this.flViewContainer.removeAllViews();
this.previousView = this.currentView;
if (this.selectedPosition >= viewCount) {
this.selectedPosition = viewCount - 1;
}
this.currentView = this.adapter.getView(this.selectedPosition, this.previousView, this);
addViewWithAnimation(this.currentView, false);
}
}
public void switchToItem(int position, boolean animate) {
if (this.adapter != null) {
int viewCount = this.adapter.getCount();
position = valueInRange(position, 0, viewCount - 1);
if (position != this.selectedPosition) {
View oldView = this.currentView;
this.currentView = this.adapter.getView(position, this.previousView, this);
this.previousView = oldView;
addViewWithAnimation(this.currentView, animate, position < this.selectedPosition);
removeViewWithAnimation(this.previousView, animate, position < this.selectedPosition);
this.selectedPosition = position;
}
}
}
private int valueInRange(int value, int min, int max) {
if (value > max) {
value = max;
} else if (value < min) {
value = min;
}
return value;
}
private void addViewWithAnimation(View view, boolean animate, boolean leftToRight) {
if (view != null) {
if(view.getParent() == null) {
this.flViewContainer.addView(view, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
if (animate) {
int start = leftToRight ? -90 : 90;
Animation rotateIn = new RotateAnimation(start, 0, this.animationPivotX, this.animationPivotY);
rotateIn.setDuration(1000);
view.startAnimation(rotateIn);
}
}
}
private void addViewWithAnimation(View view, boolean animate) {
addViewWithAnimation(view, animate, true);
}
private void removeViewWithAnimation(View view, boolean animate, boolean leftToRight) {
if (view != null) {
if (animate) {
int target = leftToRight ? 90 : -90;
Animation rotateOut = new RotateAnimation(0, target, this.animationPivotX, this.animationPivotY);
rotateOut.setDuration(1000);
rotateOut.setAnimationListener(new ViewAnimationEndListener(view) {
@Override
protected void onAnimationEnd(Animation animation, View view) {
flViewContainer.removeView(view);
}
});
view.startAnimation(rotateOut);
} else {
this.flViewContainer.removeView(view);
}
}
}
private void removeViewWithAnimation(View view, boolean animate) {
removeViewWithAnimation(view, animate, true);
}
private abstract class ViewAnimationEndListener implements Animation.AnimationListener {
private final View view;
private ViewAnimationEndListener(View view) {
this.view = view;
}
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
onAnimationEnd(animation, this.view);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
protected abstract void onAnimationEnd(Animation animation, View view);
}
private class MenuItemClickListener implements OnClickListener {
private final int position;
MenuItemClickListener(int position) {
this.position = position;
}
@Override
public void onClick(View v) {
if(adapter != null && adapter.isMenuItemEnabled(this.position) && isRotationMenuVisible()) {
switchToItem(this.position, true);
}
}
}
}
RotationMenuAdapter.java:
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
* Created by Xaver Kapeller on 26/03/14.
*/
public abstract class RotationMenuAdapter extends BaseAdapter {
public abstract View getMenuItemView(int position, View convertView, ViewGroup parent);
public abstract long getMenuItemId(int position);
public abstract boolean isMenuItemEnabled(int position);
}
自定义视图正在使用适配器和查看回收,因此您使用它的方式与使用ListView
的方式相同。由于回收的视图,它不是非常占用内存,实际上非常快。在底部创建菜单项的逻辑也在适配器中,它也使用视图回收。因此,请务必使用与实施getMenuItemView()
时相同的谨慎来实施getView()
。首先,你必须编写一个适配器:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import at.test.app.R;
import at.test.app.RotationMenu.RotationMenuAdapter;
import java.util.List;
/**
* Created by Xaver Kapeller on 26/03/14.
*/
public class TestAdapter extends RotationMenuAdapter {
private static final long TEST_VIEW_ID = 0;
private static final long DEFAULT_VIEW_ID = TEST_VIEW_ID;
private static final long TEST_MENU_ID = 0;
private static final long DEFAULT_MENU_ID = TEST_MENU_ID;
private final LayoutInflater inflater;
private final List<TestViewModel> viewModels;
public TestAdapter(Context context, List<TestViewModel> viewModels) {
this.inflater = LayoutInflater.from(context);
this.viewModels = viewModels;
}
@Override
public int getCount() {
return this.viewModels.size();
}
@Override
public Object getItem(int position) {
return this.viewModels.get(position);
}
@Override
public long getItemId(int position) {
Object viewModel = getItem(position);
if(viewModel instanceof TestViewModel) {
return TEST_VIEW_ID;
}
return DEFAULT_VIEW_ID;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(getItemId(position) == TEST_VIEW_ID) {
TestViewModel viewModel = (TestViewModel) getItem(position);
TestRow row;
if(convertView == null) {
convertView = this.inflater.inflate(TestRow.LAYOUT, parent, false);
row = new TestRow(convertView);
convertView.setTag(row);
}
row = (TestRow) convertView.getTag();
row.bind(viewModel);
}
return convertView;
}
@Override
public View getMenuItemView(int position, View convertView, ViewGroup parent) {
if(getMenuItemId(position) == TEST_MENU_ID) {
TestViewModel viewModel = (TestViewModel)getItem(position);
MenuRow row;
if(convertView == null) {
convertView = this.inflater.inflate(MenuRow.LAYOUT, parent, false);
row = new MenuRow(convertView);
convertView.setTag(row);
}
row = (MenuRow)convertView.getTag();
row.bind(viewModel);
}
return convertView;
}
@Override
public long getMenuItemId(int position) {
Object item = getItem(position);
if(item instanceof TestViewModel) {
return TEST_MENU_ID;
}
return DEFAULT_MENU_ID;
}
@Override
public boolean isMenuItemEnabled(int position) {
return true;
}
}
除了创建菜单项的额外方法外,没什么特别之处。在isMenuItemEnabled()
中,您可以根据需要添加逻辑以启用/禁用菜单项。
然后将适配器应用于视图:
List<TestViewModel> viewModels = new ArrayList<TestViewModel>();
TestViewModel menuItemOne = new TestViewModel();
menuItemOne.setMenuItemIconResId(R.drawable.icon);
viewModels.add(menuItemOne);
TestViewModel menuItemTwo = new TestViewModel();
menuItemTwo.setMenuItemIconResId(R.drawable.icon);
viewModels.add(menuItemTwo);
TestAdapter adapter = new TestAdapter(getActivity(), viewModels);
this.rotationMenu.setAdapter(adapter);
修改强>
使用wrap_content
代替match_parent
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/menuItemImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/tab_1_1" />
</RelativeLayout>
我也不确定你的layout_width
,你确定你需要match_parent
吗?我不这么认为。