FrameLayout即帧布局,以往开发的时候用的比较少,但最近做到一些弹出框的效果,就不得不使用帧布局来为底层的View来遮盖,中层用透明的view,最后再在上层铺弹出的View来达到既定的效果。
分析一下如下的一张效果图:
该View就是由 底层为粉色 覆盖上一层半透明view 然后再在上层添加一层白色背景的效果图。
以此是否可以模拟顶部弹出的弹出框呢。
public class CustomFrame extends LinearLayout{
/**
* 承载内容的主体view
* */
private FrameLayout mFrameContent;
private Context mContext;
//遮罩颜色
private int maskColor = 0x88888888;
public CustomFrame(Context context) {
this(context,null);
}
public CustomFrame(Context context, @Nullable AttributeSet attrs) {
this(context,attrs,0);
}
public CustomFrame(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
init(context,attrs);
}
/**
* 初始化View :
* 这里通过java代码,添加入内,并没有使用什么xml布局
* */
private void init(Context context, AttributeSet attrs) {
// 创建布局
mFrameContent = new FrameLayout(context);
// 设置Frame的信息包 为铺满全屏 new xxx.LayoutParams(x,y)
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
// 将信息包设置给view
mFrameContent.setLayoutParams(params);
// 将View添加给父布局
addView(mFrameContent);
}
/**
* 将底层 半透明层和上层添加入内
* */
public void setCustomFrameView(View beyondView,View topView){
mFrameContent.addView(beyondView,0);
View maskView = new View(mContext);
maskView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));
maskView.setBackgroundColor(maskColor);
mFrameContent.addView(maskView,1);
mFrameContent.addView(topView);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.zxl.myworklearning.activities.views.activities.FrameCusActivity">
<com.example.zxl.myworklearning.widget.CustomFrame
android:id="@+id/customView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.zxl.myworklearning.widget.CustomFrame>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:background="#fff"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="300dp">
<TextView
android:layout_marginTop="200dp"
android:layout_marginLeft="100dp"
android:text="FrameLayout透明度学习"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
public class FrameCusActivity extends AppCompatActivity {
private CustomFrame mCustomFrame;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame_cus);
mCustomFrame = (CustomFrame) findViewById(R.id.customView);
View view = new View(this);
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
view.setBackgroundColor(ContextCompat.getColor(this,R.color.colorAccent));
View inflate = LayoutInflater.from(this).inflate(R.layout.layout_top, null);
mCustomFrame.setCustomFrameView(view,inflate);
}
}
其实上面这些代码和在xml书写如下代码是等价的,只不过一个是自定义view一个是布局罢了,
但我们有必要学习动态添加代码并且设置相对应的属性等。而且抽离出来可以做自定义view大大提高了利用率。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.zxl.myworklearning.activities.views.activities.FrameTest2Activity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:background="@color/colorAccent"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
<View
android:background="#88888888"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:background="#fff"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="300dp">
<TextView
android:layout_marginTop="200dp"
android:layout_marginLeft="100dp"
android:text="FrameLayout透明度学习"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
总之来说帧布局还是有很大的用处的。不仅仅是应用于Fragment中吧。
紧着着我又马不停蹄的对网上的一个开源代码DropDownView进行了修改,原因是将其放入相对布局中的话,主体显示的内容View会被顶出去,而我希望是像五八一样的透明的显示,嗯,就是这样,所以我进行了如下修改。先看下效果吧:
大致说明下:主要是运用了FrameLayout的思路进行布局的重构,通过动态的方式给主体的FrameLayout添加布局,来达到主体内容居于底部,中间层透明和上层弹出的效果,然后我也修改了动画,原因是过渡动画掌握的不好,后面会进行研究。下面贴出核心代码。
/**
* @author zxl 修改版的DropDownView
*/
public class DropDownView extends RelativeLayout {
private static final int DROP_DOWN_CONTAINER_MIN_DEFAULT_VIEWS = 1;
private static final int DROP_DOWN_HEADER_CONTAINER_MIN_DEFAULT_VIEWS = 0;
/**
* 注解该View可以为空
* */
@Nullable
private View expandedView;
@Nullable
private View headerView;
private ViewGroup dropDownHeaderContainer;
private LinearLayout dropDownContainer;
private boolean isExpanded;
private DropDownListener dropDownListener;
private int backgroundColor;
private int overlayColor;
private FrameLayout mFmContainer;
private View mMaskView;
public DropDownView(Context context) {
super(context);
init(context, null);
}
public DropDownView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public DropDownView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
/**
* 目标 Api 21 Android 5.0
* */
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public DropDownView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
/**
* @return the {@link DropDownListener} that was set by you. Default is null.
* @see #setDropDownListener(DropDownListener)
*/
@Nullable
public DropDownListener getDropDownListener() {
return dropDownListener;
}
/**
* @param dropDownListener your implementation of {@link DropDownListener}.
* @see DropDownListener
*/
public void setDropDownListener(DropDownListener dropDownListener) {
this.dropDownListener = dropDownListener;
}
/**
* @return true if the view is expanded, false otherwise.
*/
public boolean isExpanded() {
return isExpanded;
}
/**
*
* @param headerView your header view
*/
public void setHeaderView(@NonNull View headerView) {
this.headerView = headerView;
/* ------ 移除所有头布局包含的控件 --- */
if (dropDownHeaderContainer.getChildCount() > DROP_DOWN_HEADER_CONTAINER_MIN_DEFAULT_VIEWS) {
for (int i = DROP_DOWN_HEADER_CONTAINER_MIN_DEFAULT_VIEWS; i < dropDownHeaderContainer.getChildCount(); i++) {
dropDownHeaderContainer.removeViewAt(i);
}
}
dropDownHeaderContainer.addView(headerView);
}
/**
* 精华设置伸展的布局
* @param expandedView your header view
*/
public void setExpandedView(@NonNull View expandedView,@NonNull View beyondView) {
this.expandedView = expandedView;
if (mFmContainer.getChildCount() > DROP_DOWN_CONTAINER_MIN_DEFAULT_VIEWS) {
for (int i = DROP_DOWN_CONTAINER_MIN_DEFAULT_VIEWS; i < dropDownContainer.getChildCount(); i++) {
mFmContainer.removeViewAt(i);
}
}
mFmContainer.addView(beyondView,0);
mMaskView = new View(getContext());
mMaskView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
mMaskView.setBackgroundColor(0x88888888);
mFmContainer.addView(mMaskView,1);
mMaskView.setOnClickListener(emptyDropDownSpaceClickListener);
mFmContainer.addView(expandedView,2);
mMaskView.setVisibility(isExpanded?View.VISIBLE:View.GONE);
expandedView.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
}
/**
* 伸展
*/
public void expandDropDown() {
if (!isExpanded && expandedView != null) {
if (dropDownListener != null) {
dropDownListener.onExpandDropDown();
}
expandedView.setVisibility(View.VISIBLE);
expandedView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_in));
mMaskView.setVisibility(VISIBLE);
mMaskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_in));
isExpanded = true;
}
}
/**
* 缩起来了
* */
public void collapseDropDown() {
if (isExpanded && expandedView != null) {
expandedView.setVisibility(View.GONE);
expandedView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_out));
mMaskView.setVisibility(GONE);
mMaskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_out));
if (dropDownListener != null) {
dropDownListener.onCollapseDropDown();
}
isExpanded = false;
}
}
/**
* 初始化自定义View
* */
private void init(Context context, AttributeSet attrs) {
handleAttrs(context, attrs);
// 注意这里是 this( 父布局是当前控件---- 一定要记得)----
inflate(getContext(), R.layout.view_ddv_drop_down, this);
bindViews();
setupViews();
}
/**
* 处理自定义的属性
* */
private void handleAttrs(Context context, AttributeSet attrs) {
if (context != null && attrs != null) {
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.DropDownView,
0, 0);
try {
backgroundColor = a.getColor(R.styleable.DropDownView_containerBackgroundColor, ContextCompat.getColor(context, R.color.dDVColorPrimary));
overlayColor = a.getColor(R.styleable.DropDownView_overlayColor, ContextCompat.getColor(context, R.color.dDVTransparentGray));
} finally {
a.recycle(); // 进行回收
}
}
// 设置默认的颜色 ---
if (backgroundColor == 0) {
backgroundColor = ContextCompat.getColor(context, R.color.dDVColorPrimary);
}
if (overlayColor == 0) {
overlayColor = ContextCompat.getColor(context, R.color.dDVTransparentGray);
}
}
private void setupViews() {
dropDownHeaderContainer.setOnClickListener(dropDownHeaderClickListener);
// 头容器
dropDownHeaderContainer.setBackgroundColor(backgroundColor);
}
private void bindViews() {
dropDownContainer = (LinearLayout) findViewById(R.id.drop_down_container);
dropDownHeaderContainer = (ViewGroup) findViewById(R.id.drop_down_header);
mFmContainer = (FrameLayout) findViewById(R.id.fmContainer);
}
private final OnClickListener dropDownHeaderClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
if (isExpanded) {
collapseDropDown();
} else {
expandDropDown();
}
}
};
private final OnClickListener emptyDropDownSpaceClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
collapseDropDown();
}
};
/**
* 设置监听回调
* */
public interface DropDownListener {
/**
* 扩张成功
* This method will only be triggered when {@link #expandDropDown()} is called successfully.
*/
void onExpandDropDown();
/**
* 折叠成功
* This method will only be triggered when {@link #collapseDropDown()} is called successfully.
*/
void onCollapseDropDown();
}
}
<?xml version="1.0" encoding="utf-8"?>
<!--
<merge /> 标签来减少视图层级结构
在Android layout文件中需要一个顶级容器来容纳其他的组件,而不能直接放置多个组件
目的是通过删减多余或者额外的层级,从而优化整个Android Layout的结构。
直接作用在父布局之下 也就是 RelativeLayout
如下面的 tools:parentTag = "android.widget.RelativeLayout" 就是很好的解释
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="android.widget.RelativeLayout">
<!-- 空背景 -->
<!-- 内容区域-->
<LinearLayout
android:id="@+id/drop_down_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:orientation="vertical">
<!-- 控件的头 -->
<RelativeLayout
android:id="@+id/drop_down_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/dDVColorPrimary"
android:gravity="center">
<!-- Will have one child for Header/Collapsed View -->
</RelativeLayout>
<FrameLayout
android:id="@+id/fmContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<!-- 这里add的布局必将置于头之下 -->
<!-- Will have one child after drop_down_header for Expanded View -->
</LinearLayout>
</merge>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.anthonyfdev.dropdownview.DropDownView
android:id="@+id/drop_down_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:containerBackgroundColor="@color/dropDownContainerColor"
app:overlayColor="@color/ovlyColor"/>
<TextView
android:text="我在底部"
android:layout_alignParentBottom="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupViews();
setupList();
View view = LayoutInflater.from(this).inflate(R.layout.layout_content, null);
dropDownView.setHeaderView(collapsedView);
dropDownView.setExpandedView(expandedView,view);
dropDownView.setDropDownListener(dropDownListener);
}
好了,就是这么多,修改的后面也用于我的项目了,读大牛的代码真的学到很多东西,我也渐渐的改变了我之前比较丑陋的代码。