Commit 783cec50 authored by wanglei's avatar wanglei

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	app/src/main/java/com/base/browserwhite/ui/activity/MainActivity.kt
parents 77f632a6 163e8389
......@@ -139,7 +139,10 @@ dependencies {
// RxJava 3.1.3
implementation("io.reactivex.rxjava3:rxjava:3.1.3")
implementation("io.reactivex.rxjava3:rxandroid:3.0.0")
//facebook
implementation("org.greenrobot:eventbus:3.0.0")
implementation("com.facebook.android:facebook-android-sdk:[8,9)")
// implementation("com.zhy:percent-support-extends:1.1.1")
}
\ No newline at end of file
......@@ -98,6 +98,12 @@
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".label.LabelActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<activity
android:name=".ui.activity.webbrowser.WebBrowserActivity"
android:exported="true"
......
package com.base.browserwhite.label;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.os.Handler;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.base.browserwhite.R;
import com.base.browserwhite.label.custom.mainActivitySimpleOnGestureListener;
import com.base.browserwhite.label.event.delThisFrag;
import com.base.browserwhite.label.event.deleteFragEvent;
import com.base.browserwhite.label.event.showDelImg;
import com.base.browserwhite.label.constance.fragConst;
import com.base.browserwhite.label.customview.PercentRelativeLayout;
import com.base.browserwhite.label.customview.verticalViewPager;
import com.base.browserwhite.label.event.baseEvent;
import com.base.browserwhite.label.event.fragEvent;
import com.base.browserwhite.label.event.slideEvent;
import com.base.browserwhite.label.event.zoomEvent;
import com.base.browserwhite.label.fragment.fragAdapter;
import com.base.browserwhite.label.fragment.mainFrag;
import static android.widget.RelativeLayout.*;
import androidx.core.view.GestureDetectorCompat;
import androidx.fragment.app.FragmentActivity;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
public class LabelActivity extends FragmentActivity {
private verticalViewPager mViewPager;
private fragAdapter fragPagerAdapter;
private TextView pagebt;
private ImageView leftbt, rightbt, setbt, homebt, delfrag, addnewpage, returnmain;
private LinearLayout llayoutviewpage, pagebarlt, mainbarlt;
private DisplayMetrics dm2;
private GestureDetectorCompat mDetector;
private PercentRelativeLayout mainrootrl;
private mainActivitySimpleOnGestureListener mainSimpleOnGestureListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.label);
for (int i = 0; i < fragConst.init_page_count; i++) {
mainFrag tmp=new mainFrag();
fragConst.fraglist.add(tmp);
fragConst.fraghashcode.add(String.valueOf(tmp.hashCode()));
}
mViewPager = (verticalViewPager) findViewById(R.id.mainviewpage);
fragPagerAdapter = new fragAdapter(this, getSupportFragmentManager());
mViewPager.setAdapter(fragPagerAdapter);
mViewPager.setOffscreenPageLimit(3);
// EventBus.getDefault().register(this);
mainSimpleOnGestureListener = new mainActivitySimpleOnGestureListener();
mDetector = new GestureDetectorCompat(this, mainSimpleOnGestureListener);
mainrootrl = (PercentRelativeLayout) findViewById(R.id.mainrootrl);
viewInit();
}
private void viewInit() {
leftbt = (ImageView) findViewById(R.id.leftbt);
rightbt = (ImageView) findViewById(R.id.rightbt);
setbt = (ImageView) findViewById(R.id.setbt);
pagebt = (TextView) findViewById(R.id.pagebt);
homebt = (ImageView) findViewById(R.id.homebt);
delfrag = (ImageView) findViewById(R.id.delfrag);
addnewpage = (ImageView) findViewById(R.id.addnewpage);
returnmain = (ImageView) findViewById(R.id.returnmain);
leftbt.setOnClickListener((View v) -> {
bthander(v.getId());
});
rightbt.setOnClickListener((View v) -> {
bthander(v.getId());
});
setbt.setOnClickListener((View v) -> {
bthander(v.getId());
});
pagebt.setOnClickListener((View v) -> {
bthander(v.getId());
});
homebt.setOnClickListener((View v) -> {
bthander(v.getId());
});
addnewpage.setOnClickListener((View v) -> {
bthander(v.getId());
});
returnmain.setOnClickListener((View v) -> {
bthander(v.getId());
});
mainbarlt = (LinearLayout) findViewById(R.id.mainbarlt);
pagebarlt = (LinearLayout) findViewById(R.id.pagebarlt);
llayoutviewpage = (LinearLayout) findViewById(R.id.llayoutviewpage);
dm2 = getResources().getDisplayMetrics();
mainrootrl.setOnTouchListener((View v, MotionEvent event) -> {
mDetector.onTouchEvent(event);
return true;
});
pagebt.setText(fragConst.fraglist.size() + "");
}
public void bthander(int id) {
if (id == R.id.leftbt) {
// 处理 leftbt 按钮点击事件
} else if (id == R.id.rightbt) {
// 处理 rightbt 按钮点击事件
} else if (id == R.id.setbt) {
// 处理 setbt 按钮点击事件
} else if (id == R.id.pagebt) {
zoomchange();
} else if (id == R.id.homebt) {
// removePage(mViewPager.getCurrentItem());
} else if (id == R.id.addnewpage) {
addNewPage();
} else if (id == R.id.returnmain) {
zoomchange();
}
}
private void addNewPage() {
mainFrag tmp=new mainFrag();
fragConst.fraghashcode.add(String.valueOf( tmp.hashCode()));
fragConst.fraglist.add(mViewPager.getCurrentItem() + 1, tmp);
fragPagerAdapter.notifyDataSetChanged();
mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1);
Handler handler = new Handler();
handler.postDelayed(() -> {
if (dm2.widthPixels - mViewPager.getWidth() < 5) {
} else {
zoomchange();
}
}, 400);
}
private void removePage(int position) {
if (position >= 0 && position < fragConst.fraglist.size()) {
if (fragConst.fraglist.size() <= 1) {
return;
}
fragConst.fraglist.remove(position);
fragConst.fraghashcode.remove(position);
fragPagerAdapter.notifyDataSetChanged();
}
}
private boolean currentIsFull = true;//当前是不是全屏
private void zoomchange() {
int thewidth = mViewPager.getWidth();
if (dm2.widthPixels - mViewPager.getWidth() < 5) {
mViewPager.setPageMargin(fragConst.page_interval);
// Logger.v("缩小 " + thewidth);
llayoutviewpage.setGravity(CENTER_IN_PARENT);
//缩小
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.8f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.8f);
ObjectAnimator scale = ObjectAnimator.ofPropertyValuesHolder(mViewPager, pvhX, pvhY);
scale.setDuration(30);
scale.start();
RelativeLayout.LayoutParams Rlparam = new RelativeLayout.LayoutParams(dm2.widthPixels * 8 / 10, dm2.heightPixels * 8 / 10);
Rlparam.addRule(CENTER_IN_PARENT);
llayoutviewpage.setLayoutParams(Rlparam);
mainSimpleOnGestureListener.setViewPagePosition(mViewPager.getWidth(), mViewPager.getHeight());
pagebarlt.setVisibility(VISIBLE);
mainbarlt.setVisibility(INVISIBLE);
EventBus.getDefault().post(new zoomEvent(false));
} else {
// Logger.v("放大 " + thewidth + " ---- " + dm2.widthPixels);
mViewPager.setPageMargin(0);
//放大到原来样子
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX", 0.8f, 1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", 0.8f, 1f);
ObjectAnimator scale = ObjectAnimator.ofPropertyValuesHolder(mViewPager, pvhX, pvhY);
scale.setDuration(30);
scale.start();
currentIsFull = true;
RelativeLayout.LayoutParams Rlparam2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
Rlparam2.addRule(CENTER_IN_PARENT);
llayoutviewpage.setLayoutParams(Rlparam2);
pagebarlt.setVisibility(INVISIBLE);
mainbarlt.setVisibility(VISIBLE);
pagebt.setText(fragConst.fraglist.size() + "");
EventBus.getDefault().post(new zoomEvent(true));
}
}
@Subscribe
public void onEventMainThread(baseEvent event) {
if (event instanceof fragEvent) {
// Toast.makeText(this, " 收到 event 数据 " + ((fragEvent) event).getFragTag(), Toast.LENGTH_SHORT).show();
if (dm2.widthPixels - mViewPager.getWidth() < 5) {
} else {
zoomchange();
}
}
if (event instanceof slideEvent) {
// Toast.makeText(this, " 收到 event 数据 " + ((slideEvent) event).getType()+" "+((slideEvent) event).getDirection(), Toast.LENGTH_SHORT).show();
switch (((slideEvent) event).getType()) {
case MotionEvent.ACTION_MOVE:
switch (((slideEvent) event).getDirection()) {
case "left":
break;
case "right":
break;
}
break;
case MotionEvent.ACTION_DOWN:
switch (((slideEvent) event).getDirection()) {
case "left":
int cItem = mViewPager.getCurrentItem();
mViewPager.setCurrentItem(cItem > 0 ? cItem - 1 : cItem);
break;
case "right":
int rItem = mViewPager.getCurrentItem();
mViewPager.setCurrentItem(rItem < fragConst.fraglist.size() - 1 ? rItem + 1 : rItem);
break;
}
break;
}
}
if (event instanceof deleteFragEvent) {
int i = 0;
String Tag = ((deleteFragEvent) event).getFragTag();
for (mainFrag temp : fragConst.fraglist) {
if (temp.getFragTag().equals(Tag)) {
Handler dohandler = new Handler();
final int page = i;
dohandler.postDelayed(() -> {
// Logger.v("删除 page " + page);
removePage(page);
}, 80);
}
i++;
}
}
if (event instanceof showDelImg) {
if (((showDelImg) event).isShow()) {
delfrag.setVisibility(VISIBLE);
} else {
delfrag.setVisibility(INVISIBLE);
}
}
if (event instanceof delThisFrag) {
removePage(mViewPager.getCurrentItem());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
fragConst.fraglist.clear();
fragConst.new_mainfrag_count = 0; //调用次数清0
}
}
package com.base.browserwhite.label.constance;
import com.base.browserwhite.label.fragment.mainFrag;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2016/8/20.
*/
public class fragConst {
public static List<mainFrag> fraglist=new ArrayList<>(); //fraglist和fraghashcode成对出现
public static List<String> fraghashcode=new ArrayList<>(); //存储对象的hashcode
public static int page_interval=40; //界面之间的间隔
public static int init_page_count=1; //初始化的界面个数
public static int new_mainfrag_count=0; // mainFrag类构造函数被调用的次数
}
package com.base.browserwhite.label.custom;
import android.view.GestureDetector;
import android.view.MotionEvent;
import com.base.browserwhite.label.event.slideEvent;
import org.greenrobot.eventbus.EventBus;
/**
* Created by Administrator on 2016/8/23.
*/
public class mainActivitySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {
private int mViewpageX,mViewpageY,mViewpageWidth,mViewpageHeight;
public void setViewPagePosition(int mViewpageWidth,int mViewpageHeight ){
this.mViewpageWidth = mViewpageWidth*7/10;
this.mViewpageHeight = mViewpageHeight*7/10;
this.mViewpageX = (mViewpageWidth /2)-(mViewpageWidth*7/10/2 );
this.mViewpageY = (mViewpageHeight /2)-(mViewpageHeight*7/10/2 );;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// Logger.v("onFling "+ "x: "+e1.getX() +" y: "+e1.getY() +"x: "+e2.getX() +" y: "+e2.getY() );
JudgeSendEvent("onFling",e1,e2);
return super.onFling(e1, e2, velocityX, velocityY);
}
@Override
public boolean onDown(MotionEvent e) {
// Logger.v("onDown "+ "x: "+e.getX() +" y: "+e.getY() );
JudgeSendEvent("onDown",e,null);
return super.onDown(e);
}
//判断是否发出事件
private void JudgeSendEvent(String action,MotionEvent e1, MotionEvent e2){
switch (action ){
case "onFling":
if(e1.getX()<mViewpageX && e1.getY()>mViewpageY && e1.getY()<(mViewpageY+mViewpageHeight) ){
if( e2.getX()-e1.getX() >20 ){
// Logger.v(" 向右滑动 ");
EventBus.getDefault().post(new slideEvent(MotionEvent.ACTION_MOVE, "right")); // 发送消息
}else if(e1.getX()-e2.getX() >20){
// Logger.v(" 向左滑动 ");
EventBus.getDefault().post(new slideEvent(MotionEvent.ACTION_MOVE,"left" ));
}
}
else if(e1.getX()>(mViewpageX+ mViewpageWidth)&& e1.getY()>mViewpageY && e1.getY()<(mViewpageY+mViewpageHeight) ){
if( e2.getX()-e1.getX() >20 ){
EventBus.getDefault().post(new slideEvent(MotionEvent.ACTION_MOVE, "right"));
// Logger.v(" 向右滑动 ");
}else if(e1.getX()-e2.getX() >20){
// Logger.v(" 向左滑动 ");
EventBus.getDefault().post(new slideEvent(MotionEvent.ACTION_MOVE, "left"));
}
}
break;
case "onDown":
// Logger.v( " onDown "+e1.getX()+" "+e1.getY()
// +"\n mViewpageX "+mViewpageX +" mViewpageWidth "+mViewpageWidth
// +"\n mViewpageY "+mViewpageY +" mViewpageWidth "+mViewpageHeight);
if(e1.getX()<mViewpageX && e1.getY()>mViewpageY && e1.getY()<(mViewpageY+mViewpageHeight) ){
// Logger.v( " onDown left " );
EventBus.getDefault().post(new slideEvent(MotionEvent.ACTION_DOWN, "left"));
}
else if(e1.getX()>(mViewpageX+ mViewpageWidth)&& e1.getY()>mViewpageY && e1.getY()<(mViewpageY+mViewpageHeight) ){
EventBus.getDefault().post(new slideEvent(MotionEvent.ACTION_DOWN, "right"));
//Logger.v( " onDown right " );
}
break;
}
}
}
package com.base.browserwhite.label.customview;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.view.MarginLayoutParamsCompat;
import androidx.core.view.ViewCompat;
import com.base.browserwhite.R;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Helper for layouts that want to support percentage based dimensions.
* <p/>
* <p>This class collects utility methods that are involved in extracting percentage based dimension
* attributes and applying them to ViewGroup's children. If you would like to implement a layout
* that supports percentage based dimensions, you need to take several steps:
* <p/>
* <ol>
* <li> You need a {@link ViewGroup.LayoutParams} subclass in your ViewGroup that implements
* <li> In your {@code LayoutParams(Context c, AttributeSet attrs)} constructor create an instance
* of {@link PercentLayoutHelper.PercentLayoutInfo} by calling
* {@link PercentLayoutHelper#getPercentLayoutInfo(Context, AttributeSet)}. Return this
* object from {@code public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo()}
* <li> Override
* with a single line implementation {@code PercentLayoutHelper.fetchWidthAndHeight(this, a,
* widthAttr, heightAttr);}
* <li> In your ViewGroup override {@link ViewGroup#generateLayoutParams(AttributeSet)} to return
* your LayoutParams.
* pattern:
* <pre class="prettyprint">
* protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
* mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
* super.onMeasure(widthMeasureSpec, heightMeasureSpec);
* if (mHelper.handleMeasuredStateTooSmall()) {
* super.onMeasure(widthMeasureSpec, heightMeasureSpec);
* }
* }
* </pre>
* implement following pattern:
* <pre class="prettyprint">
* protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
* super.onLayout(changed, left, top, right, bottom);
* mHelper.restoreOriginalParams();
* }
* </pre>
* </ol>
*/
public class PercentLayoutHelper
{
private static final String TAG = "PercentLayout";
private final ViewGroup mHost;
private static int mWidthScreen;
private static int mHeightScreen;
public PercentLayoutHelper(ViewGroup host)
{
mHost = host;
getScreenSize();
}
private void getScreenSize()
{
WindowManager wm = (WindowManager) mHost.getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
mWidthScreen = outMetrics.widthPixels;
mHeightScreen = outMetrics.heightPixels;
}
/**
* Helper method to be called from override
* that reads layout_width and layout_height attribute values without throwing an exception if
* they aren't present.
*/
public static void fetchWidthAndHeight(ViewGroup.LayoutParams params, TypedArray array,
int widthAttr, int heightAttr)
{
params.width = array.getLayoutDimension(widthAttr, 0);
params.height = array.getLayoutDimension(heightAttr, 0);
}
/**
* Iterates over children and changes their width and height to one calculated from percentage
* values.
*
* @param widthMeasureSpec Width MeasureSpec of the parent ViewGroup.
* @param heightMeasureSpec Height MeasureSpec of the parent ViewGroup.
*/
public void adjustChildren(int widthMeasureSpec, int heightMeasureSpec)
{
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "adjustChildren: " + mHost + " widthMeasureSpec: "
+ View.MeasureSpec.toString(widthMeasureSpec) + " heightMeasureSpec: "
+ View.MeasureSpec.toString(heightMeasureSpec));
}
int widthHint = View.MeasureSpec.getSize(widthMeasureSpec);
int heightHint = View.MeasureSpec.getSize(heightMeasureSpec);
if (Log.isLoggable(TAG, Log.DEBUG))
Log.d(TAG, "widthHint = " + widthHint + " , heightHint = " + heightHint);
for (int i = 0, N = mHost.getChildCount(); i < N; i++)
{
View view = mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "should adjust " + view + " " + params);
}
if (params instanceof PercentLayoutParams)
{
PercentLayoutInfo info =
((PercentLayoutParams) params).getPercentLayoutInfo();
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "using " + info);
}
if (info != null)
{
supportTextSize(widthHint, heightHint, view, info);
supportPadding(widthHint, heightHint, view, info);
supportMinOrMaxDimesion(widthHint, heightHint, view, info);
if (params instanceof ViewGroup.MarginLayoutParams)
{
info.fillMarginLayoutParams((ViewGroup.MarginLayoutParams) params,
widthHint, heightHint);
} else
{
info.fillLayoutParams(params, widthHint, heightHint);
}
}
}
}
}
private void supportPadding(int widthHint, int heightHint, View view, PercentLayoutInfo info)
{
int left = view.getPaddingLeft(), right = view.getPaddingRight(), top = view.getPaddingTop(), bottom = view.getPaddingBottom();
PercentLayoutInfo.PercentVal percentVal = info.paddingLeftPercent;
if (percentVal != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, percentVal.basemode);
left = (int) (base * percentVal.percent);
}
percentVal = info.paddingRightPercent;
if (percentVal != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, percentVal.basemode);
right = (int) (base * percentVal.percent);
}
percentVal = info.paddingTopPercent;
if (percentVal != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, percentVal.basemode);
top = (int) (base * percentVal.percent);
}
percentVal = info.paddingBottomPercent;
if (percentVal != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, percentVal.basemode);
bottom = (int) (base * percentVal.percent);
}
view.setPadding(left, top, right, bottom);
}
private void supportMinOrMaxDimesion(int widthHint, int heightHint, View view, PercentLayoutInfo info)
{
try
{
Class clazz = view.getClass();
invokeMethod("setMaxWidth", widthHint, heightHint, view, clazz, info.maxWidthPercent);
invokeMethod("setMaxHeight", widthHint, heightHint, view, clazz, info.maxHeightPercent);
invokeMethod("setMinWidth", widthHint, heightHint, view, clazz, info.minWidthPercent);
invokeMethod("setMinHeight", widthHint, heightHint, view, clazz, info.minHeightPercent);
} catch (NoSuchMethodException e)
{
e.printStackTrace();
} catch (InvocationTargetException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
private void invokeMethod(String methodName, int widthHint, int heightHint, View view, Class clazz, PercentLayoutInfo.PercentVal percentVal) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
{
if (Log.isLoggable(TAG, Log.DEBUG))
Log.d(TAG, methodName + " ==> " + percentVal);
if (percentVal != null)
{
Method setMaxWidthMethod = clazz.getMethod(methodName, int.class);
setMaxWidthMethod.setAccessible(true);
int base = getBaseByModeAndVal(widthHint, heightHint, percentVal.basemode);
setMaxWidthMethod.invoke(view, (int) (base * percentVal.percent));
}
}
private void supportTextSize(int widthHint, int heightHint, View view, PercentLayoutInfo info)
{
//textsize percent support
PercentLayoutInfo.PercentVal textSizePercent = info.textSizePercent;
if (textSizePercent == null) return;
int base = getBaseByModeAndVal(widthHint, heightHint, textSizePercent.basemode);
float textSize = (int) (base * textSizePercent.percent);
//Button 和 EditText 是TextView的子类
if (view instanceof TextView)
{
((TextView) view).setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
}
}
private static int getBaseByModeAndVal(int widthHint, int heightHint, PercentLayoutInfo.BASEMODE basemode)
{
switch (basemode)
{
case BASE_HEIGHT:
return heightHint;
case BASE_WIDTH:
return widthHint;
case BASE_SCREEN_WIDTH:
return mWidthScreen;
case BASE_SCREEN_HEIGHT:
return mHeightScreen;
}
return 0;
}
/**
* Constructs a PercentLayoutInfo from attributes associated with a View. Call this method from
* {@code LayoutParams(Context c, AttributeSet attrs)} constructor.
*/
public static PercentLayoutInfo getPercentLayoutInfo(Context context,
AttributeSet attrs)
{
PercentLayoutInfo info = null;
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PercentLayout_Layout);
info = setWidthAndHeightVal(array, info);
info = setMarginRelatedVal(array, info);
info = setTextSizeSupportVal(array, info);
info = setMinMaxWidthHeightRelatedVal(array, info);
info = setPaddingRelatedVal(array, info);
array.recycle();
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "constructed: " + info);
}
return info;
}
private static PercentLayoutInfo setWidthAndHeightVal(TypedArray array, PercentLayoutInfo info)
{
PercentLayoutInfo.PercentVal percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_widthPercent, true);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent width: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.widthPercent = percentVal;
}
percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_heightPercent, false);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent height: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.heightPercent = percentVal;
}
return info;
}
private static PercentLayoutInfo setTextSizeSupportVal(TypedArray array, PercentLayoutInfo info)
{
//textSizePercent 默认以高度作为基准
PercentLayoutInfo.PercentVal percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_textSizePercent, false);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent text size: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.textSizePercent = percentVal;
}
return info;
}
private static PercentLayoutInfo setMinMaxWidthHeightRelatedVal(TypedArray array, PercentLayoutInfo info)
{
//maxWidth
PercentLayoutInfo.PercentVal percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_maxWidthPercent,
true);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.maxWidthPercent = percentVal;
}
//maxHeight
percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_maxHeightPercent,
false);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.maxHeightPercent = percentVal;
}
//minWidth
percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_minWidthPercent,
true);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.minWidthPercent = percentVal;
}
//minHeight
percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_minHeightPercent,
false);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.minHeightPercent = percentVal;
}
return info;
}
private static PercentLayoutInfo setMarginRelatedVal(TypedArray array, PercentLayoutInfo info)
{
//默认margin参考宽度
PercentLayoutInfo.PercentVal percentVal =
getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_marginPercent,
true);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent margin: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.leftMarginPercent = percentVal;
info.topMarginPercent = percentVal;
info.rightMarginPercent = percentVal;
info.bottomMarginPercent = percentVal;
}
percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_marginLeftPercent, true);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent left margin: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.leftMarginPercent = percentVal;
}
percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_marginTopPercent, false);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent top margin: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.topMarginPercent = percentVal;
}
percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_marginRightPercent, true);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent right margin: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.rightMarginPercent = percentVal;
}
percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_marginBottomPercent, false);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent bottom margin: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.bottomMarginPercent = percentVal;
}
percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_marginStartPercent, true);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent start margin: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.startMarginPercent = percentVal;
}
percentVal = getPercentVal(array, R.styleable.PercentLayout_Layout_layout_marginEndPercent, true);
if (percentVal != null)
{
if (Log.isLoggable(TAG, Log.VERBOSE))
{
Log.v(TAG, "percent end margin: " + percentVal.percent);
}
info = checkForInfoExists(info);
info.endMarginPercent = percentVal;
}
return info;
}
/**
* 设置paddingPercent相关属性
*
* @param array
* @param info
*/
private static PercentLayoutInfo setPaddingRelatedVal(TypedArray array, PercentLayoutInfo info)
{
//默认padding以宽度为标准
PercentLayoutInfo.PercentVal percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_paddingPercent,
true);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.paddingLeftPercent = percentVal;
info.paddingRightPercent = percentVal;
info.paddingBottomPercent = percentVal;
info.paddingTopPercent = percentVal;
}
percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_paddingLeftPercent,
true);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.paddingLeftPercent = percentVal;
}
percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_paddingRightPercent,
true);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.paddingRightPercent = percentVal;
}
percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_paddingTopPercent,
true);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.paddingTopPercent = percentVal;
}
percentVal = getPercentVal(array,
R.styleable.PercentLayout_Layout_layout_paddingBottomPercent,
true);
if (percentVal != null)
{
info = checkForInfoExists(info);
info.paddingBottomPercent = percentVal;
}
return info;
}
private static PercentLayoutInfo.PercentVal getPercentVal(TypedArray array, int index, boolean baseWidth)
{
String sizeStr = array.getString(index);
PercentLayoutInfo.PercentVal percentVal = getPercentVal(sizeStr, baseWidth);
return percentVal;
}
@NonNull
private static PercentLayoutInfo checkForInfoExists(PercentLayoutInfo info)
{
info = info != null ? info : new PercentLayoutInfo();
return info;
}
private static final String REGEX_PERCENT = "^(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)%([s]?[wh]?)$";
/**
* widthStr to PercentVal
* <br/>
* eg: 35%w => new PercentVal(35, true)
*
* @param percentStr
* @param isOnWidth
* @return
*/
private static PercentLayoutInfo.PercentVal getPercentVal(String percentStr, boolean isOnWidth)
{
//valid param
if (percentStr == null)
{
return null;
}
Pattern p = Pattern.compile(REGEX_PERCENT);
Matcher matcher = p.matcher(percentStr);
if (!matcher.matches())
{
throw new RuntimeException("the value of layout_xxxPercent invalid! ==>" + percentStr);
}
int len = percentStr.length();
//extract the float value
String floatVal = matcher.group(1);
String lastAlpha = percentStr.substring(len - 1);
float percent = Float.parseFloat(floatVal) / 100f;
PercentLayoutInfo.PercentVal percentVal = new PercentLayoutInfo.PercentVal();
percentVal.percent = percent;
if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.SW))
{
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_SCREEN_WIDTH;
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.SH))
{
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_SCREEN_HEIGHT;
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.PERCENT))
{
if (isOnWidth)
{
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_WIDTH;
} else
{
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_HEIGHT;
}
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.W))
{
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_WIDTH;
} else if (percentStr.endsWith(PercentLayoutInfo.BASEMODE.H))
{
percentVal.basemode = PercentLayoutInfo.BASEMODE.BASE_HEIGHT;
} else
{
throw new IllegalArgumentException("the " + percentStr + " must be endWith [%|w|h|sw|sh]");
}
return percentVal;
}
/**
* Iterates over children and restores their original dimensions that were changed for
* percentage values. Calling this method only makes sense if you previously called
* {@link PercentLayoutHelper#adjustChildren(int, int)}.
*/
public void restoreOriginalParams()
{
for (int i = 0, N = mHost.getChildCount(); i < N; i++)
{
View view = mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "should restore " + view + " " + params);
}
if (params instanceof PercentLayoutParams)
{
PercentLayoutInfo info =
((PercentLayoutParams) params).getPercentLayoutInfo();
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "using " + info);
}
if (info != null)
{
if (params instanceof ViewGroup.MarginLayoutParams)
{
info.restoreMarginLayoutParams((ViewGroup.MarginLayoutParams) params);
} else
{
info.restoreLayoutParams(params);
}
}
}
}
}
/**
* Iterates over children and checks if any of them would like to get more space than it
* received through the percentage dimension.
* <p/>
* If you are building a layout that supports percentage dimensions you are encouraged to take
* advantage of this method. The developer should be able to specify that a child should be
* remeasured by adding normal dimension attribute with {@code wrap_content} value. For example
* he might specify child's attributes as {@code app:layout_widthPercent="60%p"} and
* {@code android:layout_width="wrap_content"}. In this case if the child receives too little
* space, it will be remeasured with width set to {@code WRAP_CONTENT}.
*
* @return True if the measure phase needs to be rerun because one of the children would like
* to receive more space.
*/
public boolean handleMeasuredStateTooSmall()
{
boolean needsSecondMeasure = false;
for (int i = 0, N = mHost.getChildCount(); i < N; i++)
{
View view = mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "should handle measured state too small " + view + " " + params);
}
if (params instanceof PercentLayoutParams)
{
PercentLayoutInfo info =
((PercentLayoutParams) params).getPercentLayoutInfo();
if (info != null)
{
if (shouldHandleMeasuredWidthTooSmall(view, info))
{
needsSecondMeasure = true;
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
if (shouldHandleMeasuredHeightTooSmall(view, info))
{
needsSecondMeasure = true;
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
}
}
}
}
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "should trigger second measure pass: " + needsSecondMeasure);
}
return needsSecondMeasure;
}
private static boolean shouldHandleMeasuredWidthTooSmall(View view, PercentLayoutInfo info)
{
int state = ViewCompat.getMeasuredWidthAndState(view) & ViewCompat.MEASURED_STATE_MASK;
if (info == null || info.widthPercent == null)
{
return false;
}
return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.widthPercent.percent >= 0 &&
info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
}
private static boolean shouldHandleMeasuredHeightTooSmall(View view, PercentLayoutInfo info)
{
int state = ViewCompat.getMeasuredHeightAndState(view) & ViewCompat.MEASURED_STATE_MASK;
if (info == null || info.heightPercent == null)
{
return false;
}
return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.heightPercent.percent >= 0 &&
info.mPreservedParams.height == ViewGroup.LayoutParams.WRAP_CONTENT;
}
/**
* Container for information about percentage dimensions and margins. It acts as an extension
* for {@code LayoutParams}.
*/
public static class PercentLayoutInfo
{
private enum BASEMODE
{
BASE_WIDTH, BASE_HEIGHT, BASE_SCREEN_WIDTH, BASE_SCREEN_HEIGHT;
/**
* width_parent
*/
public static final String PERCENT = "%";
/**
* width_parent
*/
public static final String W = "w";
/**
* height_parent
*/
public static final String H = "h";
/**
* width_screen
*/
public static final String SW = "sw";
/**
* height_screen
*/
public static final String SH = "sh";
}
public static class PercentVal
{
public float percent = -1;
public BASEMODE basemode;
public PercentVal()
{
}
public PercentVal(float percent, BASEMODE baseMode)
{
this.percent = percent;
this.basemode = baseMode;
}
@Override
public String toString()
{
return "PercentVal{" +
"percent=" + percent +
", basemode=" + basemode.name() +
'}';
}
}
public PercentVal widthPercent;
public PercentVal heightPercent;
public PercentVal leftMarginPercent;
public PercentVal topMarginPercent;
public PercentVal rightMarginPercent;
public PercentVal bottomMarginPercent;
public PercentVal startMarginPercent;
public PercentVal endMarginPercent;
public PercentVal textSizePercent;
//1.0.4 those attr for some views' setMax/min Height/Width method
public PercentVal maxWidthPercent;
public PercentVal maxHeightPercent;
public PercentVal minWidthPercent;
public PercentVal minHeightPercent;
//1.0.6 add padding supprot
public PercentVal paddingLeftPercent;
public PercentVal paddingRightPercent;
public PercentVal paddingTopPercent;
public PercentVal paddingBottomPercent;
/* package */ final ViewGroup.MarginLayoutParams mPreservedParams;
public PercentLayoutInfo()
{
mPreservedParams = new ViewGroup.MarginLayoutParams(0, 0);
}
/**
* Fills {@code ViewGroup.LayoutParams} dimensions based on percentage values.
*/
public void fillLayoutParams(ViewGroup.LayoutParams params, int widthHint,
int heightHint)
{
// Preserve the original layout params, so we can restore them after the measure step.
mPreservedParams.width = params.width;
mPreservedParams.height = params.height;
if (widthPercent != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, widthPercent.basemode);
params.width = (int) (base * widthPercent.percent);
}
if (heightPercent != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, heightPercent.basemode);
params.height = (int) (base * heightPercent.percent);
}
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "after fillLayoutParams: (" + params.width + ", " + params.height + ")");
}
}
/**
* Fills {@code ViewGroup.MarginLayoutParams} dimensions and margins based on percentage
* values.
*/
public void fillMarginLayoutParams(ViewGroup.MarginLayoutParams params, int widthHint,
int heightHint)
{
fillLayoutParams(params, widthHint, heightHint);
// Preserver the original margins, so we can restore them after the measure step.
mPreservedParams.leftMargin = params.leftMargin;
mPreservedParams.topMargin = params.topMargin;
mPreservedParams.rightMargin = params.rightMargin;
mPreservedParams.bottomMargin = params.bottomMargin;
MarginLayoutParamsCompat.setMarginStart(mPreservedParams,
MarginLayoutParamsCompat.getMarginStart(params));
MarginLayoutParamsCompat.setMarginEnd(mPreservedParams,
MarginLayoutParamsCompat.getMarginEnd(params));
if (leftMarginPercent != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, leftMarginPercent.basemode);
params.leftMargin = (int) (base * leftMarginPercent.percent);
}
if (topMarginPercent != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, topMarginPercent.basemode);
params.topMargin = (int) (base * topMarginPercent.percent);
}
if (rightMarginPercent != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, rightMarginPercent.basemode);
params.rightMargin = (int) (base * rightMarginPercent.percent);
}
if (bottomMarginPercent != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, bottomMarginPercent.basemode);
params.bottomMargin = (int) (base * bottomMarginPercent.percent);
}
if (startMarginPercent != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, startMarginPercent.basemode);
MarginLayoutParamsCompat.setMarginStart(params,
(int) (base * startMarginPercent.percent));
}
if (endMarginPercent != null)
{
int base = getBaseByModeAndVal(widthHint, heightHint, endMarginPercent.basemode);
MarginLayoutParamsCompat.setMarginEnd(params,
(int) (base * endMarginPercent.percent));
}
if (Log.isLoggable(TAG, Log.DEBUG))
{
Log.d(TAG, "after fillMarginLayoutParams: (" + params.width + ", " + params.height
+ ")");
}
}
@Override
public String toString()
{
return "PercentLayoutInfo{" +
"widthPercent=" + widthPercent +
", heightPercent=" + heightPercent +
", leftMarginPercent=" + leftMarginPercent +
", topMarginPercent=" + topMarginPercent +
", rightMarginPercent=" + rightMarginPercent +
", bottomMarginPercent=" + bottomMarginPercent +
", startMarginPercent=" + startMarginPercent +
", endMarginPercent=" + endMarginPercent +
", textSizePercent=" + textSizePercent +
", maxWidthPercent=" + maxWidthPercent +
", maxHeightPercent=" + maxHeightPercent +
", minWidthPercent=" + minWidthPercent +
", minHeightPercent=" + minHeightPercent +
", paddingLeftPercent=" + paddingLeftPercent +
", paddingRightPercent=" + paddingRightPercent +
", paddingTopPercent=" + paddingTopPercent +
", paddingBottomPercent=" + paddingBottomPercent +
", mPreservedParams=" + mPreservedParams +
'}';
}
/**
* Restores original dimensions and margins after they were changed for percentage based
* values. Calling this method only makes sense if you previously called
* {@link PercentLayoutHelper.PercentLayoutInfo#fillMarginLayoutParams}.
*/
public void restoreMarginLayoutParams(ViewGroup.MarginLayoutParams params)
{
restoreLayoutParams(params);
params.leftMargin = mPreservedParams.leftMargin;
params.topMargin = mPreservedParams.topMargin;
params.rightMargin = mPreservedParams.rightMargin;
params.bottomMargin = mPreservedParams.bottomMargin;
MarginLayoutParamsCompat.setMarginStart(params,
MarginLayoutParamsCompat.getMarginStart(mPreservedParams));
MarginLayoutParamsCompat.setMarginEnd(params,
MarginLayoutParamsCompat.getMarginEnd(mPreservedParams));
}
/**
* Restores original dimensions after they were changed for percentage based values. Calling
* this method only makes sense if you previously called
* {@link PercentLayoutHelper.PercentLayoutInfo#fillLayoutParams}.
*/
public void restoreLayoutParams(ViewGroup.LayoutParams params)
{
params.width = mPreservedParams.width;
params.height = mPreservedParams.height;
}
}
/**
* If a layout wants to support percentage based dimensions and use this helper class, its
* {@code LayoutParams} subclass must implement this interface.
* <p/>
* Your {@code LayoutParams} subclass should contain an instance of {@code PercentLayoutInfo}
* and the implementation of this interface should be a simple accessor.
*/
public interface PercentLayoutParams
{
PercentLayoutInfo getPercentLayoutInfo();
}
}
\ No newline at end of file
package com.base.browserwhite.label.customview;
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
/**
* Subclass of {@link RelativeLayout} that supports percentage based dimensions and
* margins.
*
* You can specify dimension or a margin of child by using attributes with "Percent" suffix. Follow
* this example:
*
* <pre class="prettyprint">
* &lt;android.support.percent.PercentRelativeLayout
* 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"/&gt
* &lt;ImageView
* app:layout_widthPercent="50%"
* app:layout_heightPercent="50%"
* app:layout_marginTopPercent="25%"
* app:layout_marginLeftPercent="25%"/&gt
* &lt;/android.support.percent.PercentFrameLayout/&gt
* </pre>
*
* The attributes that you can use are:
* <ul>
* <li>{@code layout_widthPercent}
* <li>{@code layout_heightPercent}
* <li>{@code layout_marginPercent}
* <li>{@code layout_marginLeftPercent}
* <li>{@code layout_marginTopPercent}
* <li>{@code layout_marginRightPercent}
* <li>{@code layout_marginBottomPercent}
* <li>{@code layout_marginStartPercent}
* <li>{@code layout_marginEndPercent}
* </ul>
*
* It is not necessary to specify {@code layout_width/height} if you specify {@code
* layout_widthPercent.} However, if you want the view to be able to take up more space than what
* percentage value permits, you can add {@code layout_width/height="wrap_content"}. In that case
* if the percentage size is too small for the View's content, it will be resized using
* {@code wrap_content} rule.
*/
public class PercentRelativeLayout extends RelativeLayout {
private final PercentLayoutHelper mHelper = new PercentLayoutHelper(this);
public PercentRelativeLayout(Context context) {
super(context);
}
public PercentRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PercentRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mHelper.handleMeasuredStateTooSmall()) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mHelper.restoreOriginalParams();
}
public static class LayoutParams extends RelativeLayout.LayoutParams
implements PercentLayoutHelper.PercentLayoutParams {
private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
@Override
public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
return mPercentLayoutInfo;
}
@Override
protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
PercentLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
}
}
}
\ No newline at end of file
package com.base.browserwhite.label.customview;
import android.content.Context;
import android.util.AttributeSet;
import androidx.viewpager.widget.ViewPager;
/**
* Created by Administrator on 2016/8/24.
*/
/*
* 在普通 ViewPager 上实现向上滑动删除 一个Item
*/
public class verticalViewPager extends ViewPager {
public verticalViewPager(Context context) {
super(context);
}
public verticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
package com.base.browserwhite.label.event;
/**
* Created by Administrator on 2016/8/23.
*/
public class baseEvent {
}
package com.base.browserwhite.label.event;
/**
* Created by Administrator on 2016/8/25.
*/
public class delThisFrag extends baseEvent {
//fragment发出,通知anctvity删除自己
}
package com.base.browserwhite.label.event;
/**
* Created by Administrator on 2016/8/24.
*/
public class deleteFragEvent extends baseEvent {
//如果fragment 上滑到一半,就会发出删除信号
String fragTag;
public deleteFragEvent(String fragTag) {
this.fragTag = fragTag;
}
public String getFragTag() {
return fragTag;
}
public void setFragTag(String fragTag) {
this.fragTag = fragTag;
}
}
package com.base.browserwhite.label.event;
/**
* Created by Administrator on 2016/8/23.
*/
public class fragEvent extends baseEvent{
//用于传递 fragment的tag
String fragTag;
public fragEvent(String fragTag) {
this.fragTag = fragTag;
}
public String getFragTag() {
return fragTag;
}
public void setFragTag(String fragTag) {
this.fragTag = fragTag;
}
}
package com.base.browserwhite.label.event;
/**
* Created by Administrator on 2016/8/25.
*/
//显示删除按钮
public class showDelImg extends baseEvent {
private boolean isShow;
public showDelImg(boolean isShow) {
this.isShow = isShow;
}
public boolean isShow() {
return isShow;
}
public void setIsShow(boolean isShow) {
this.isShow = isShow;
}
}
package com.base.browserwhite.label.event;
/**
* Created by Administrator on 2016/8/23.
*/
//viewpager缩小后点击 viewpager控件的左边或者右边 发出的事件
public class slideEvent extends baseEvent {
private int type; //事件类型:点击 ACTION_DOWN ,滑动 ACTION_MOVE
private String direction;//点击位置 或者 滑动方向
public slideEvent(int type, String direction) {
this.type = type;
this.direction = direction;
}
public int getType() {
return type;
}
public String getDirection() {
return direction;
}
public void setType(int type) {
this.type = type;
}
public void setDirection(String direction) {
this.direction = direction;
}
}
package com.base.browserwhite.label.event;
/**
* Created by Administrator on 2016/8/25.
*/
public class zoomEvent extends baseEvent {
//viewpager当前的状态,放大或缩小
private boolean isMatchParent; //viewpager 当前是不是 MatchParent
public zoomEvent(boolean isMatchParent) {
this.isMatchParent = isMatchParent;
}
public boolean isMatchParent() {
return isMatchParent;
}
public void setIsMatchParent(boolean isMatchParent) {
this.isMatchParent = isMatchParent;
}
}
package com.base.browserwhite.label.fragment;
import android.view.MotionEvent;
import android.view.View;
import androidx.fragment.app.Fragment;
/**
* Created by Administrator on 2016/8/23.
*/
public class baseFrag extends Fragment implements View.OnTouchListener {
protected float point_x, point_y; //手指按下的位置
private boolean flag;
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
point_x = event.getX();
point_y = event.getY();
flag = false;
}
return true;
}
}
package com.base.browserwhite.label.fragment;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import com.base.browserwhite.label.constance.fragConst;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
/**
* Created by Administrator on 2016/8/20.
*/
public class fragAdapter extends FragmentStatePagerAdapter {
private Context context;
private FragmentManager fm;
public fragAdapter(Context context,FragmentManager fm) {
super(fm);
this.context = context;
this.fm=fm;
}
@Override
public Fragment getItem(int position) {
return fragConst.fraglist.get(position);
}
@Override
public int getCount() {
// Logger.v("fragConst.fraglist.size() "+fragConst.fraglist.size());
return fragConst.fraglist.size();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
return super.instantiateItem(container, position);
}
@Override
public int getItemPosition(Object object) {
// try {
// Method method = object.getClass().getMethod(("getFragTag"),new Class[0] );
// String tag= (String) method.invoke(object,new Object[0]);
// if( isDel ){
// if( tag.equals(""+id ) ){
// Logger.d("删除项tag= "+tag+ " id= " + id );
// return POSITION_NONE;
// }else {
// return POSITION_UNCHANGED;
// }
// }else {
// return POSITION_UNCHANGED;
// }
// } catch (NoSuchMethodException e) {
// e.printStackTrace();
// } catch (InvocationTargetException e) {
// Logger.d("getItemPosition InvocationTargetException" );
// e.printStackTrace();
// } catch (IllegalAccessException e) {
// Logger.d("getItemPosition IllegalAccessException" );
// e.printStackTrace();
// }
//需要实现一种机制避免更新所有的fragment
return POSITION_NONE;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
}
package com.base.browserwhite.label.fragment;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.base.browserwhite.R;
import com.base.browserwhite.label.event.delThisFrag;
import com.base.browserwhite.label.event.deleteFragEvent;
import com.base.browserwhite.label.event.fragEvent;
import com.base.browserwhite.label.event.showDelImg;
import com.base.browserwhite.label.event.zoomEvent;
import com.base.browserwhite.label.constance.fragConst;
import com.base.browserwhite.label.event.baseEvent;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by Administrator on 2016/8/20.
*/
public class mainFrag extends baseFrag {
private RelativeLayout mainrlt;
private TextView showtitletv;
private LinearLayout showtitlelt;
private FrameLayout rootlt;
private DisplayMetrics dm2;
private String fragTag = "";
private ImageView delthispage;
private boolean isNewFragment = false;
private int color;
public mainFrag() {
this.fragTag = fragConst.new_mainfrag_count + "";
fragConst.new_mainfrag_count++;
isNewFragment = true;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_label, container, false);
mainrlt = (RelativeLayout) view.findViewById(R.id.mainrlt);
mainrlt.setOnTouchListener(this);
rootlt = (FrameLayout) view.findViewById(R.id.rootlt);
rootlt.setOnTouchListener(this);
delthispage = (ImageView) view.findViewById(R.id.delthispage);
showtitlelt = (LinearLayout) view.findViewById(R.id.showtitlelt);
showtitletv = (TextView) view.findViewById(R.id.showtitletv);
EventBus.getDefault().register(this);
init(view);
return view;
}
private void init(View view) {
dm2 = getResources().getDisplayMetrics();
TextView showtag = (TextView) view.findViewById(R.id.showtag);
showtag.setText("当前fragment " + getFragTag());
delthispage.setOnClickListener(View -> {
delAnime();
new Handler().postDelayed(() -> {
EventBus.getDefault().post(new delThisFrag()); // 发送消息
}, 300);
});
if ((fragConst.new_mainfrag_count > 1) && isNewFragment) {
//缩小
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX", 0.1f, 1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", 0.1f, 1f);
ObjectAnimator scale = ObjectAnimator.ofPropertyValuesHolder(rootlt, pvhX, pvhY);
scale.setDuration(50);
scale.start();
Random random = new Random();
color = Color.rgb(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
isNewFragment = false;
if (color != 0) {
mainrlt.setBackgroundColor(color);
}
}
public String getFragTag() { // 被反射的方法
return fragTag;
}
public void setFragTag(String fragTag) {
this.fragTag = fragTag;
}
private float mov_x, mov_y; //相对于手指移动了的位置
private int left, right, top, bottom;
private List<int[]> positionlist = new ArrayList<>();
@Override
public boolean onTouch(View v, MotionEvent event) {
super.onTouch(v, event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
positionlist.clear();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
// Logger.v("x: " + event.getX() + " y: " + event.getY());
mov_x = event.getX() - super.point_x;
mov_y = event.getY() - super.point_y;
left = mainrlt.getLeft();
right = mainrlt.getRight();
top = mainrlt.getTop();
bottom = mainrlt.getBottom();
if (Math.abs(dm2.widthPixels - mainrlt.getWidth()) > 5) {
mainrlt.layout(left, top + (int) mov_y, right, bottom + (int) mov_y);
int[] position = {left, top + (int) mov_y, right, bottom + (int) mov_y};
positionlist.add(position);
// Logger.v("left " + position[0] + " top " + position[1] + " right " + position[2] + " bottom " + position[3] );
if (Math.abs(position[1]) > mainrlt.getWidth() / 2) {
// Logger.v("- 显示 删除 按钮 -");
EventBus.getDefault().post(new showDelImg(true)); // 发送消息
} else {
EventBus.getDefault().post(new showDelImg(false)); // 发送消息
}
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
if (positionlist.size() >= 2) {
if (fragConst.fraglist.size()>1 && Math.abs(positionlist.get(positionlist.size() - 1)[1]) > mainrlt.getWidth() / 2) {
// Logger.v("- 删除 fragment -");
delAnime();
EventBus.getDefault().post(new showDelImg(false)); // 发送消息
new Handler().postDelayed(() -> {
EventBus.getDefault().post(new deleteFragEvent(getFragTag())); // 发送消息
}, 200);
return true;
}
} else {
//放大或者缩小fragment
EventBus.getDefault().post(new fragEvent(getFragTag())); // 发送消息
}
for (int i = positionlist.size() - 1; i >= 0; i--) {
mainrlt.layout(positionlist.get(i)[0], positionlist.get(i)[1], positionlist.get(i)[2], positionlist.get(i)[3]);
}
mainrlt.layout(0, 0, mainrlt.getWidth(), mainrlt.getHeight());
}
return true;
}
//删除动画
private void delAnime() {
if (fragConst.fraglist.size() <= 1) {
return;
}
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.01f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.01f);
ObjectAnimator scalexy = ObjectAnimator.ofPropertyValuesHolder(mainrlt, pvhX, pvhY);
ObjectAnimator scale = ObjectAnimator.ofFloat(mainrlt, "translationY", 0, -2500);
scale.setDuration(200);
scalexy.setDuration(200);
scale.start();
scalexy.start();
}
@Subscribe
public void onEventMainThread(baseEvent event) {
// Toast.makeText(getActivity(), " 收到 event 数据 ", 0).show();
if (event instanceof zoomEvent) {
if (((zoomEvent) event).isMatchParent()) {
showtitlelt.setVisibility(View.INVISIBLE);
} else {
showtitlelt.setVisibility(View.VISIBLE);
}
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
EventBus.getDefault().unregister(this);
}
}
......@@ -92,6 +92,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
addDeskShortCut()
}
......
<FrameLayout 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"
android:id="@+id/rootlt"
>
<RelativeLayout
android:id="@+id/mainrlt"
android:background="#a0FFFF00"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/showtitlelt"
android:visibility="invisible"
android:orientation="vertical"
android:background="#50000000"
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="LeLo"
android:id="@+id/showtitletv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:textSize="40dp"
android:id="@+id/showtag"
android:text="showtag"
android:textColor="#FFFFFF"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:orientation="vertical"
android:background="#50000000"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_margin="5dp"
android:id="@+id/delthispage"
android:layout_gravity="center_horizontal"
android:background="@mipmap/reddit_115_local"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<com.base.browserwhite.label.customview.PercentRelativeLayout 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:id="@+id/mainrootrl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#b0000000"
android:clipChildren="false"
android:layerType="software">
<LinearLayout
android:id="@+id/llayoutviewpage"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerInParent="true"
android:clickable="true"
android:clipChildren="false"
android:orientation="vertical"
app:layout_heightPercent="100%h"
app:layout_widthPercent="100%w">
<com.base.browserwhite.label.customview.verticalViewPager
android:id="@+id/mainviewpage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"></com.base.browserwhite.label.customview.verticalViewPager>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/delfrag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="15dp"
android:background="@mipmap/del_chip"
android:visibility="invisible" />
</RelativeLayout>
<LinearLayout
android:id="@+id/mainbarlt"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:orientation="vertical"
app:layout_heightPercent="8%h"
app:layout_widthPercent="100%w">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:layout_weight="1"
android:background="#000000">
</View>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="horizontal">
<ImageView
android:id="@+id/leftbt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@mipmap/ebay"
app:layout_marginLeftPercent="20%w" />
<ImageView
android:id="@+id/rightbt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@mipmap/right_n" />
<ImageView
android:id="@+id/setbt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@mipmap/search_bookmark" />
<TextView
android:id="@+id/pagebt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@mipmap/s_del"
android:gravity="center"
android:text="1" />
<ImageView
android:id="@+id/homebt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@mipmap/home" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/pagebarlt"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
android:orientation="vertical"
android:visibility="invisible"
app:layout_heightPercent="8%h"
app:layout_widthPercent="40%w">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/addnewpage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@mipmap/m_add_widget"
app:layout_marginLeftPercent="20%w" />
<ImageView
android:id="@+id/returnmain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@mipmap/reddit_115_local" />
</LinearLayout>
</LinearLayout>
</com.base.browserwhite.label.customview.PercentRelativeLayout>
......@@ -4,4 +4,31 @@
<attr name="appWidgetInnerRadius" format="dimension" />
<attr name="appWidgetRadius" format="dimension" />
</declare-styleable>
<declare-styleable name="PercentLayout_Layout">
<attr name="layout_widthPercent" format="string"/>
<attr name="layout_heightPercent" format="string"/>
<attr name="layout_marginPercent" format="string"/>
<attr name="layout_marginLeftPercent" format="string"/>
<attr name="layout_marginTopPercent" format="string"/>
<attr name="layout_marginRightPercent" format="string"/>
<attr name="layout_marginBottomPercent" format="string"/>
<attr name="layout_marginStartPercent" format="string"/>
<attr name="layout_marginEndPercent" format="string"/>
<attr name="layout_textSizePercent" format="string"/>
<attr name="layout_maxWidthPercent" format="string"/>
<attr name="layout_maxHeightPercent" format="string"/>
<attr name="layout_minWidthPercent" format="string"/>
<attr name="layout_minHeightPercent" format="string"/>
<attr name="layout_paddingPercent" format="string"/>
<attr name="layout_paddingTopPercent" format="string"/>
<attr name="layout_paddingBottomPercent" format="string"/>
<attr name="layout_paddingLeftPercent" format="string"/>
<attr name="layout_paddingRightPercent" format="string"/>
</declare-styleable>
</resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment