Let’s start with a quick review of the Builder pattern
define
Separating a complex object representation from the build process allows the same build process to create different representations
scenario
- The same method, different execution sequence, produce different event results
- Multiple parts can be assembled into an object, but produce different results
- Product classes are complex, or the order in which product classes are called has different effects
- When initializing an object is complex, for example, many parameters have default values
UML diagrams
- Product class: Generally a relatively complex object, that is to say, the process of creating the object is complex, there will be a lot of code. In this class diagram, the product class is a concrete class, not an abstract class. In real programming, a product class may consist of an abstract class with its different implementations, or of multiple abstract classes with their implementations.
- Abstract Builder: The purpose of the abstract builder is to delegate the concrete process of construction to its subclasses. It’s easier to scale. There are usually at least two abstract methods, one to build the product and one to return the product.
- Builder: Implements all unimplemented methods of an abstract class. Specifically, there are generally two tasks: building a product; Return to the finished product.
- The director class is responsible for calling the appropriate builder to build the product. The director class generally does not depend on the product class. The builder class interacts directly with the director class. In general, the director class is used to encapsulate mutable parts of a program.
In the actual development process, the role of Director is often ignored, and the object is directly assembled by Builder. Builder is usually called by chain, with a simpler structure and finer control over the product
advantages
- Good encapsulation, the client does not have to care about the internal composition of the product details
- The builder is independent and easy to expand
disadvantages
Generates redundant Builder objects and Direactor objects, consuming memory
Universal popover encapsulation
The popover scene conforms to Builder mode scenario 4, so we use builder mode to encapsulate this (omitting the director and abstract constructor classes). Let’s look at the calling code below
MainActivity.java
package cn.llj.pop.demo;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity
{
private MyPopWindow mPopWindow;
private View mPopView;
private TextView mPopTv;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPopView = View.inflate(this, R.layout.pop_view, null);
mPopTv=mPopView.findViewById(R.id.tv);
mPopTv.setOnClickListener(new View.OnClickListener()// Click the control inside the popover, the popover disappears
{
@Override
public void onClick(View view)
{
if(mPopWindow ! =null&& mPopWindow.isShowing()) mPopWindow.dismiss(); }}); }public void showPop(View view)
{
if(mPopWindow ! =null)
mPopWindow.show();
else
{ // If the parameters are consistent with the default values, no further configuration is required
mPopWindow = new MyPopWindow.Builder(this)
.setLayoutView(mPopView)// Set the popover layout
.setOutsideTouchable(true)// Whether the popover window is clickable or not
.setBgTranslucent(true)// Whether the pop-up window is translucent
.setHideStateBar(false)// Whether to hide status bar
.setAnimStyle(R.style.pop_anim_style)// Set the popover animation
.setHeight(400)// Set the popover height to px
.setWidth(ViewGroup.LayoutParams.MATCH_PARENT)// Set the popover width to the same width as the screen
.setOrientation(Gravity.BOTTOM)Gravity.BOTTOM pops up, Gravity.RIGHT pops up
.setPopDismissListener(new MyPopWindow.OnPopDismissListener()// Set the popover close callback
{
@Override
public void onDismiss(a)
{
Toast.makeText(MainActivity.this."Popover is closed.",Toast.LENGTH_SHORT).show();
}
})
.build();
mPopWindow.show();
/ / mPopWindow. Show (10, 20); // Set the distance between the popover and the screen}}@Override
protected void onDestroy(a)
{
if(mPopWindow ! =null)
mPopWindow.destroy();// Popover destruction to prevent memory leaks
super.onDestroy(); }}Copy the code
- Custom popover classes
MyPopWindow.java
package cn.llj.pop.demo;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;
/** * Created by LLJ on 2019/4/2. * desc: Created by LLJ on 2019/4/2. * desc: Created by LLJ on 2019/4/2
public class MyPopWindow implements PopupWindow.OnDismissListener.ValueAnimator
.AnimatorUpdateListener
{
private final int ALPHA_ANIMATOR_DURATION = 200;// Semi-transparent animation disappear time
private static boolean mOutsideTouchable = true;
private static boolean mFocusable = true;
private static boolean mIsHideStateBar = false;
private static View mLayoutView;
private static int mWidth = ViewGroup.LayoutParams.MATCH_PARENT;//px
private static int mHeight = ViewGroup.LayoutParams.MATCH_PARENT;//px
private static int mAnimStyle = R.style.pop_anim_style;
private PopupWindow mPopWindow;
private ValueAnimator mBgAlphaAnimator;
private static Context mContext;
private static OnPopDismissListener mPopDismissListener;
private static boolean mIsBgTranslucent = true;
private static int mOrientation = Gravity.BOTTOM;
public MyPopWindow(a)
{
mPopWindow = new PopupWindow(mLayoutView, mWidth, mHeight);
mPopWindow.setAnimationStyle(mAnimStyle);
mPopWindow.setFocusable(mFocusable);
mPopWindow.setOutsideTouchable(mOutsideTouchable);
mPopWindow.setOnDismissListener(this);
}
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
if(mContext ! =null)
{
((Activity) mContext).getWindow().getAttributes().alpha = (float) animation .getAnimatedValue(); ((Activity) mContext).getWindow().setAttributes(((Activity) mContext).getWindow() .getAttributes()); }}@Override
public void onDismiss(a)
{
if (mIsBgTranslucent)
{
mBgAlphaAnimator = ValueAnimator.ofFloat(0.5 f.1.0 f);
mBgAlphaAnimator.start();
mBgAlphaAnimator.setDuration(ALPHA_ANIMATOR_DURATION);
mBgAlphaAnimator.addUpdateListener(this);
}
if(mPopDismissListener ! =null)
mPopDismissListener.onDismiss();
}
public void show(a)
{
if(mPopWindow ! =null&& mLayoutView ! =null && !mPopWindow.isShowing())
{
setAnimAndStateBar();
mPopWindow.showAtLocation(mLayoutView, mOrientation, 0.0); }}/** * The distance from the screen *@param xoff
* @param yoff
*/
public void show(int xoff, int yoff)
{
if(mPopWindow ! =null&& mLayoutView ! =null&&! mPopWindow.isShowing()) { setAnimAndStateBar(); mPopWindow.showAtLocation(mLayoutView, mOrientation, xoff, yoff); }}private void setAnimAndStateBar(a)
{
if (mIsBgTranslucent)
{
mBgAlphaAnimator = ValueAnimator.ofFloat(1.0 f.0.5 f);
mBgAlphaAnimator.setDuration(ALPHA_ANIMATOR_DURATION);
mBgAlphaAnimator.start();
mBgAlphaAnimator.addUpdateListener(this);
}
if(mIsHideStateBar) { ((Activity) mContext).getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); }}/**
* 弹窗关闭
*/
public void dismiss(a)
{
if(mPopWindow ! =null)
mPopWindow.dismiss();
}
/** * popover destruction to prevent memory leaks */
public void destroy(a)
{
if (mPopWindow.isShowing())
mPopWindow.dismiss();
mPopWindow = null;
mContext = null;
mBgAlphaAnimator = null;
}
public boolean isShowing(a)
{
returnmPopWindow ! =null && mPopWindow.isShowing();
}
/** * Listener that is called when this popup window is dismissed. */
public interface OnPopDismissListener
{
/** * Called when this popup window is dismissed. */
void onDismiss(a);
}
public static class Builder
{
public Builder(Context context)
{
if (context == null| |! (contextinstanceof Activity) || ((Activity) context)
.isFinishing())
{
throw new RuntimeException("activity is invalidate which can not create a " +
"popupwindow:" + context);
}
mContext = context;
}
/** * popover direction **@param orientation Gravity.BOTTOM Gravity.RIGHT
* @return* /
public Builder setOrientation(int orientation)
{
mOrientation = orientation;
return this;
}
public Builder setFocusable(boolean focusable)
{
mFocusable = focusable;
return this;
}
/** * Whether to hide the status bar **@param hideStateBar
* @return* /
public Builder setHideStateBar(boolean hideStateBar)
{
mIsHideStateBar = hideStateBar;
return this;
}
public Builder setOutsideTouchable(boolean outsideTouchable)
{
mOutsideTouchable = outsideTouchable;
return this;
}
public Builder setLayoutView(View layout)
{
mLayoutView = layout;
return this;
}
public Builder setWidth(int width)
{
mWidth = width;
return this;
}
public Builder setHeight(int height)
{
mHeight = height;
return this;
}
/** * set to disappear animation, default bottom-up **@param animStyle
* @return* /
public Builder setAnimStyle(int animStyle)
{
mAnimStyle = animStyle;
return this;
}
public Builder setBgTranslucent(boolean isBgTranslucent)
{
mIsBgTranslucent = isBgTranslucent;
return this;
}
public Builder setPopDismissListener(OnPopDismissListener listener)
{
mPopDismissListener = listener;
return this;
}
public MyPopWindow build(a)
{
return newMyPopWindow(); }}}Copy the code
- Here preset several types of animation, according to the actual business to expand
style.xml
<resources>
<! -- Base application theme. -->
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<! -- Customize your theme here. -->
</style>
<! -- Popup animation at the bottom -->
<style name="pop_anim_style" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/pop_enter_anim</item>
<item name="android:windowExitAnimation">@anim/pop_exit_anim</item>
</style>
<! -- Right popup animation -->
<style name="pop_right_anim_style" parent="android:Animation">
<item name="android:windowEnterAnimation">@anim/pop_right_enter_anim</item>
<item name="android:windowExitAnimation">@anim/pop_right_exit_anim</item>
</style>
<! Zoom in on top right popup animation -->
<style name="pop_fade_anim_style">
<item name="android:windowEnterAnimation">@anim/pop_fade_in</item>
<item name="android:windowExitAnimation">@anim/pop_fade_out</item>
</style>
</resources>
Copy the code
- Related animation files
pop_enter_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromYDelta="100%"
android:toYDelta="0" />
</set>
Copy the code
pop_exit_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromYDelta="0"
android:toYDelta="100%" />
</set>
Copy the code
pop_fade_in.xml
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="0.001"
android:toXScale="1.0"
android:fromYScale="0.001"
android:toYScale="1.0"
android:pivotX="100%"
android:pivotY="10%"
android:duration="200" />
Copy the code
pop_fade_out.xml
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="0.001"
android:fromYScale="1.0"
android:toYScale="0.001"
android:pivotX="100%"
android:pivotY="10%"
android:duration="200" />
Copy the code
pop_right_enter_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromXDelta="100%"
android:toXDelta="0" />
<!-- <alpha
android:duration="200"
android:fromAlpha="0.0"
android:toAlpha="1.0" />-->
</set>
Copy the code
pop_right_exit_anim.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromXDelta="0"
android:toXDelta="100%" />
</set>
Copy the code
The Builder pattern in Android source code
- AlertDialog
The following is an AlertDialog source code structure:
See the source code for details, and the examples in this article are equivalent to a simplified version of AlertDialog
- Image loading framework Glide, ImageLoader and so on