android动画送礼物,Android仿直播类app赠送礼物功能

直播界面

实现的是播放本地的视频文件:

/**

* 直播界面,用于对接直播功能

*/

public class LiveFrag extends Fragment {

private ImageView img_thumb;

private VideoView video_view;

@Nullable

@Override

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

View view = inflater.inflate(R.layout.frag_live, null);

img_thumb = view.findViewById(R.id.img_thumb);

img_thumb.setVisibility(View.GONE);

video_view = view.findViewById(R.id.video_view);

video_view.setVisibility(View.VISIBLE);

video_view.setVideoURI(Uri.parse("android.resource://" + getActivity().getPackageName() + "/" + R.raw.video_1));

video_view.start();

video_view.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

@Override

public void onCompletion(MediaPlayer mp) {

video_view.setVideoURI(Uri.parse("android.resource://" + getActivity().getPackageName() + "/" + R.raw.video_1));

//或 //mVideoView.setVideoPath(Uri.parse(_filePath));

video_view.start();

}

});

return view;

}

}

布局文件 frag_live.xml 如下:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/video_view"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:clickable="false"

android:focusable="false"

android:visibility="gone" />

android:id="@+id/img_thumb"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:clickable="false"

android:focusable="false"

android:scaleType="centerCrop"

android:src="@mipmap/img_video_1"

android:visibility="visible" />

滑动隐藏效果

需要实现的效果如下:

6ce71635f6f9ba8369a7647e40fe60d5.gif

自定义DialogFragment,使用ViewPager,第一个为空的Fragment,第二个为我们需要的Fragment,左右滑动来切换显示和隐藏效果。

观众功能交互页面 InteractiveFrag 如下:

/**

* 观众功能交互页面, 滑动隐藏效果

*/

public class InteractiveFrag extends DialogFragment {

public View view;

public Context myContext;

private ViewPager vp_interactive;

private LayerFrag layerFrag;

@Override

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

view = inflater.inflate(R.layout.frag_interactive, null);

// 初始化

initView();

initData();

return view;

}

/**

* 初始化View

*/

public void initView() {

vp_interactive = view.findViewById(R.id.vp_interactive);

}

/**

* 初始化数据

*/

public void initData() {

// EmptyFrag:什么都没有

// LayerFrag:交互界面

// 这样就达到了滑动隐藏交互的需求

vp_interactive.setAdapter(new FragmentPagerAdapter(getChildFragmentManager()) {

@Override

public int getCount() {

return 2;

}

@Override

public Fragment getItem(int position) {

if (position == 0) {

return new EmptyFrag(); // 返回空界面的fragment

} else if (position == 1) {

return layerFrag = new LayerFrag(); // 返回交互界面的frag

} else { // 设置默认

return new EmptyFrag();

}

}

});

// 设置默认显示交互界面

vp_interactive.setCurrentItem(1);

// 同时将界面改为resize已达到软键盘弹出时Fragment不会跟随移动

getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

}

@Override

public Dialog onCreateDialog(Bundle savedInstanceState) {

// 设置DialogFragment的样式,这里的代码最好还是用我的,大家不要改动

Dialog dialog = new Dialog(getActivity(), R.style.MainDialog) {

@Override

public void onBackPressed() {

super.onBackPressed();

getActivity().finish();

}

};

return dialog;

}

}

frag_interactive.xml文件如下:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

android:id="@+id/vp_interactive"

android:layout_width="match_parent"

android:layout_height="match_parent" />

用户交互页 LayerFrag:

public class LayerFrag extends Fragment {

@Nullable

@Override

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

return inflater.inflate(R.layout.frag_layer, null);

}

}

frag_layer:

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/ll_anchor"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="10dp"

android:paddingTop="10dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerVertical="true"

android:background="@drawable/bg_radius_top_black"

android:gravity="center_vertical"

android:orientation="vertical"

android:paddingLeft="55dp"

android:paddingTop="2dp"

android:paddingRight="10dp"

android:paddingBottom="2dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="十三妹哦"

android:textColor="@android:color/white"

android:textSize="12sp" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:gravity="center_vertical"

android:orientation="horizontal">

android:layout_width="35dp"

android:layout_height="20dp"

android:src="@drawable/hani_icon_tag_exp" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="5dp"

android:text="17万"

android:textColor="@android:color/white"

android:textSize="10sp" />

android:id="@+id/lv_anchorIcon"

android:layout_width="50dp"

android:layout_height="50dp"

android:src="@drawable/zf"

app:border_color="@color/colorWhite"

app:border_width="1dp" />

android:id="@+id/hlv_audience"

android:layout_width="match_parent"

android:layout_height="45dp"

android:layout_marginLeft="10dp" />

android:id="@+id/rl_num"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_below="@+id/ll_anchor"

android:layout_marginTop="5dp"

android:paddingLeft="10dp"

android:paddingRight="10dp">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="@drawable/bg_radius_bottom_pink"

android:gravity="center_vertical"

android:paddingLeft="10dp"

android:paddingTop="2dp"

android:paddingRight="10dp"

android:paddingBottom="2dp">

android:layout_width="20dp"

android:layout_height="10dp"

android:src="@drawable/molive_icon_charm_lv_20" />

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="5dp"

android:text="小时榜单第5名"

android:textColor="#fff"

android:textSize="10sp" />

android:id="@+id/tv_momocode"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentRight="true"

android:layout_centerVertical="true"

android:background="@drawable/bg_radius_top_black"

android:paddingLeft="10dp"

android:paddingTop="2dp"

android:paddingRight="10dp"

android:paddingBottom="2dp"

android:text="MoMo: 12345678"

android:textColor="@android:color/white"

android:textSize="10sp" />

android:id="@+id/ll_gift_group"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_above="@+id/lv_message"

android:layout_marginTop="10dp"

android:layout_marginBottom="10dp"

android:animateLayoutChanges="true"

android:gravity="top"

android:orientation="vertical" />

android:id="@+id/lv_message"

android:layout_width="230dp"

android:layout_height="150dp"

android:layout_above="@+id/fl_bottom"

android:layout_marginLeft="10dp"

android:cacheColorHint="#00000000"

android:divider="@null"

android:dividerHeight="5dp"

android:listSelector="#00000000"

android:scrollbarStyle="outsideOverlay"

android:scrollbars="none"

android:transcriptMode="normal" />

android:id="@+id/fl_bottom"

android:layout_width="match_parent"

android:layout_height="70dp"

android:layout_alignParentStart="true"

android:layout_alignParentBottom="true">

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@android:color/transparent"

android:gravity="center_vertical"

android:orientation="horizontal"

android:paddingLeft="10dp"

android:paddingRight="10dp">

android:id="@+id/tv_chat"

android:layout_width="40dp"

android:layout_height="70dp"

android:gravity="center"

android:text="聊天"

android:textColor="#333"

android:textSize="10sp" />

android:layout_width="0dp"

android:layout_height="1dp"

android:layout_weight="1" />

android:id="@+id/btn_gift01"

android:layout_width="40dp"

android:layout_height="70dp"

android:layout_marginRight="5dp"

android:gravity="center"

android:text="送香皂"

android:textColor="#333"

android:textSize="12sp" />

android:id="@+id/btn_gift02"

android:layout_width="40dp"

android:layout_height="70dp"

android:layout_marginRight="5dp"

android:gravity="center"

android:text="送玫瑰"

android:textColor="#333"

android:textSize="12sp" />

android:id="@+id/btn_gift03"

android:layout_width="40dp"

android:layout_height="70dp"

android:layout_marginRight="5dp"

android:gravity="center"

android:text="送爱心"

android:textColor="#333"

android:textSize="12sp" />

android:id="@+id/btn_gift04"

android:layout_width="40dp"

android:layout_height="70dp"

android:layout_marginRight="5dp"

android:gravity="center"

android:text="送蛋糕"

android:textColor="#333"

android:textSize="12sp" />

android:id="@+id/ll_inputparent"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_marginTop="5dp"

android:background="@android:color/white"

android:paddingLeft="10dp"

android:paddingRight="10dp"

android:visibility="gone">

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center_vertical"

android:orientation="horizontal">

android:id="@+id/et_chat"

android:layout_width="0dp"

android:layout_height="wrap_content"

android:layout_weight="1"

android:background="@android:color/white"

android:hint="在此输入你要说的话!"

android:maxLength="30"

android:paddingTop="10dp"

android:paddingBottom="10dp"

android:textColor="#888889"

android:textColorHint="#c8c8c8"

android:textSize="12sp" />

android:id="@+id/tv_send"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="10dp"

android:background="@android:color/holo_blue_bright"

android:paddingLeft="10dp"

android:paddingTop="5dp"

android:paddingRight="10dp"

android:paddingBottom="5dp"

android:text="发送"

android:textColor="@android:color/white"

android:textSize="12sp" />

EmptyFrag:

/**

* 空的fragment

*/

public class EmptyFrag extends Fragment {

@Nullable

@Override

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

return inflater.inflate(R.layout.frag_empty, null);

}

}

frag_empty.xml:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@android:color/transparent"

android:orientation="vertical">

在MainActivity中使用FrameLayout布局,将观众功能交互页面 InteractiveFrag 覆盖在 直播页面LiveFrag上面。

MainActivity:

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// 加载直播fragment

LiveFrag liveFrag = new LiveFrag();

getSupportFragmentManager().beginTransaction().add(R.id.fl_root, liveFrag).commit();

// 加载

new InteractiveFrag().show(getSupportFragmentManager(), "InteractiveFrag");

}

}

activity_main.xml :

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/fl_root"

android:layout_width="match_parent"

android:layout_height="match_parent" />

用户交互页实现

MagicTextView动画效果

MagicTextView代码在文章最后展示。

我们先实现如下动画效果

dc05632ec167b4d1d0c735e1944989c0.gif

android:id="@+id/mtv_giftNum"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerVertical="true"

android:layout_marginLeft="5dp"

android:layout_toRightOf="@+id/rlparent"

android:includeFontPadding="false"

android:text="x1"

android:textColor="@android:color/holo_red_dark"

android:textSize="30sp"

android:textStyle="bold"

app:strokeColor="@android:color/white"

app:strokeJoinStyle="miter"

app:strokeWidth="2" />

动画:

public class NumberAnim {

private Animator lastAnimator;

public void showAnimator(View v) {

if (lastAnimator != null) {

lastAnimator.removeAllListeners();

lastAnimator.cancel();

lastAnimator.end();

}

ObjectAnimator animScaleX = ObjectAnimator.ofFloat(v, "scaleX", 1.3f, 1.0f);

ObjectAnimator animScaleY = ObjectAnimator.ofFloat(v, "scaleY", 1.3f, 1.0f);

AnimatorSet animSet = new AnimatorSet();

animSet.playTogether(animScaleX, animScaleY);

animSet.setDuration(200);

lastAnimator = animSet;

animSet.start();

}

}

mtv_giftNum.setText("x" + count);

giftNumberAnim = new NumberAnim(); // 初始化数字动画

mtv_giftNum.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

count++;

mtv_giftNum.setText("x" + count);

giftNumberAnim.showAnimator(mtv_giftNum);

}

});

礼物进入时动画

a060aef13d27972c816c9cbb84643af2.gif

进入动画设置为decelerate_interpolator减速插值器:

android:duration="500"

android:fromXDelta="-100%p"

android:interpolator="@android:anim/decelerate_interpolator"

android:toYDelta="0%p">

/**

* 刷礼物的方法

*/

private void showGift(String tag) {

View newGiftView = ll_gift_group.findViewWithTag(tag);

// 是否有该tag类型的礼物

if (newGiftView == null) {

// 获取礼物

newGiftView = getNewGiftView(tag);

ll_gift_group.addView(newGiftView);

// 播放动画

newGiftView.startAnimation(inAnim);

final MagicTextView mtv_giftNum = newGiftView.findViewById(R.id.mtv_giftNum);

inAnim.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

}

@Override

public void onAnimationRepeat(Animation animation) {

}

@Override

public void onAnimationEnd(Animation animation) {

giftNumberAnim.showAnimator(mtv_giftNum);

}

});

} else {

// 如果列表中已经有了该类型的礼物,则不再新建,直接拿出

// 更新标识,记录最新修改的时间,用于回收判断

ImageView iv_gift = newGiftView.findViewById(R.id.iv_gift);

iv_gift.setTag(System.currentTimeMillis());

// 更新标识,更新记录礼物个数

MagicTextView mtv_giftNum = newGiftView.findViewById(R.id.mtv_giftNum);

int giftCount = (int) mtv_giftNum.getTag() + 1; // 递增

mtv_giftNum.setText("x" + giftCount);

mtv_giftNum.setTag(giftCount);

giftNumberAnim.showAnimator(mtv_giftNum);

}

}

/**

* 获取礼物

*/

private View getNewGiftView(String tag) {

// 添加标识, 该view若在layout中存在,就不在生成(用于findViewWithTag判断是否存在)

View giftView = LayoutInflater.from(myContext).inflate(R.layout.item_gift, null);

giftView.setTag(tag);

// 添加标识, 记录生成时间,回收时用于判断是否是最新的,回收最老的

ImageView iv_gift = giftView.findViewById(R.id.iv_gift);

iv_gift.setTag(System.currentTimeMillis());

// 添加标识,记录礼物个数

MagicTextView mtv_giftNum = giftView.findViewById(R.id.mtv_giftNum);

mtv_giftNum.setTag(1);

mtv_giftNum.setText("x1");

switch (tag) {

case "gift01":

iv_gift.setImageResource(GiftIcon[0]);

break;

case "gift02":

iv_gift.setImageResource(GiftIcon[1]);

break;

case "gift03":

iv_gift.setImageResource(GiftIcon[2]);

break;

case "gift04":

iv_gift.setImageResource(GiftIcon[3]);

break;

}

LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

lp.topMargin = 10;

giftView.setLayoutParams(lp);

return giftView;

}

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.btn_gift01: // 礼物1,送香皂

showGift("gift01");

break;

case R.id.btn_gift02: // 礼物2,送玫瑰

showGift("gift02");

break;

case R.id.btn_gift03: // 礼物3,送爱心

showGift("gift03");

break;

case R.id.btn_gift04: // 礼物4,送蛋糕

showGift("gift04");

break;

}

}

礼物移出动画

实现的效果如下:

659b849e3875bc820785fc037ee7c2bf.gif

礼物移出时使用accelerate_interpolator加速差值器

android:duration="500"

android:fromYDelta="0%p"

android:interpolator="@android:anim/accelerate_interpolator"

android:toYDelta="-100%p">

/**

* 移除礼物列表里的giftView

*/

private void removeGiftView(final int index) {

// 移除列表,外加退出动画

final View removeGiftView = ll_gift_group.getChildAt(index);

outAnim.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

}

@Override

public void onAnimationRepeat(Animation animation) {

}

@Override

public void onAnimationEnd(Animation animation) {

ll_gift_group.removeViewAt(index);

}

});

// 开启动画,因为定时原因,所以可能是在子线程

getActivity().runOnUiThread(new Runnable() {

@Override

public void run() {

removeGiftView.startAnimation(outAnim);

}

});

}

如果显示的礼物大于3种,就将最早的那种礼物移除:

// 是否有该tag类型的礼物

if (newGiftView == null) {

// 判断礼物列表是否已经有3个了,如果有那么删除掉一个没更新过的, 然后再添加新进来的礼物,始终保持只有3个

if (ll_gift_group.getChildCount() >= 3) {

// 获取前2个元素的最后更新时间

View giftView01 = ll_gift_group.getChildAt(0);

ImageView iv_gift01 = giftView01.findViewById(R.id.iv_gift);

long lastTime1 = (long) iv_gift01.getTag();

View giftView02 = ll_gift_group.getChildAt(1);

ImageView iv_gift02 = giftView02.findViewById(R.id.iv_gift);

long lastTime2 = (long) iv_gift02.getTag();

if (lastTime1 > lastTime2) { // 如果第二个View显示的时间比较长

removeGiftView(1);

} else { // 如果第一个View显示的时间长

removeGiftView(0);

}

}

...

开启定时清理礼物列表

礼物显示超过一定时间,自动将礼物在礼物列表中移除:

/**

* 定时清理礼物列表信息

*/

private void clearTiming() {

Timer timer = new Timer();

timer.schedule(new TimerTask() {

@Override

public void run() {

int childCount = ll_gift_group.getChildCount();

long nowTime = System.currentTimeMillis();

for (int i = 0; i < childCount; i++) {

View childView = ll_gift_group.getChildAt(i);

ImageView iv_gift = (ImageView) childView.findViewById(R.id.iv_gift);

long lastUpdateTime = (long) iv_gift.getTag();

// 更新超过3秒就刷新

if (nowTime - lastUpdateTime >= 3000) {

removeGiftView(i);

}

}

}

}, 0, 3000);

}

cd70c9c09d95c4d59bc2a6e32d886517.gif

聊天实现

2c437a9d98517c9f76e3bf8503b32fad.gif

case R.id.tv_chat:// 聊天

tv_chat.setVisibility(View.GONE);

ll_inputparent.setVisibility(View.VISIBLE);

ll_inputparent.requestFocus(); // 获取焦点

showKeyboard();

break;

case R.id.tv_send:// 发送消息

String chatMsg = et_chat.getText().toString();

if (!TextUtils.isEmpty(chatMsg)) {

messageData.add("小明: " + chatMsg);

et_chat.setText("");

messageAdapter.NotifyAdapter(messageData);

lv_message.setSelection(messageData.size());

}

hideKeyboard();

break;

/**

* 显示软键盘

*/

private void showKeyboard() {

InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);

imm.showSoftInput(et_chat, InputMethodManager.SHOW_FORCED);

}

/**

* 隐藏软键盘

*/

public void hideKeyboard() {

InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);

imm.hideSoftInputFromWindow(et_chat.getWindowToken(), 0);

}

view.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if (ll_inputparent.getVisibility() == View.VISIBLE) {

tv_chat.setVisibility(View.VISIBLE);

ll_inputparent.setVisibility(View.GONE);

hideKeyboard();

}

}

});

// 软键盘监听

SoftKeyBoardListener.setListener(getActivity(), new SoftKeyBoardListener.OnSoftKeyBoardChangeListener() {

@Override

public void keyBoardShow(int height) {/*软键盘显示:执行隐藏title动画,并修改listview高度和装载礼物容器的高度*/

// 输入文字时的界面退出动画

AnimatorSet animatorSetHide = new AnimatorSet();

ObjectAnimator leftOutAnim = ObjectAnimator.ofFloat(rl_num, "translationX", 0, -rl_num.getWidth());

ObjectAnimator topOutAnim = ObjectAnimator.ofFloat(ll_anchor, "translationY", 0, -ll_anchor.getHeight());

animatorSetHide.playTogether(leftOutAnim, topOutAnim);

animatorSetHide.setDuration(300);

animatorSetHide.start();

// 改变listview的高度

dynamicChangeListviewH(90);

dynamicChangeGiftParentH(true);

}

@Override

public void keyBoardHide(int height) {/*软键盘隐藏:隐藏聊天输入框并显示聊天按钮,执行显示title动画,并修改listview高度和装载礼物容器的高度*/

tv_chat.setVisibility(View.VISIBLE);

ll_inputparent.setVisibility(View.GONE);

// 输入文字时的界面进入时的动画

AnimatorSet animatorSetShow = new AnimatorSet();

ObjectAnimator leftInAnim = ObjectAnimator.ofFloat(rl_num, "translationX", -rl_num.getWidth(), 0);

ObjectAnimator topInAnim = ObjectAnimator.ofFloat(ll_anchor, "translationY", -ll_anchor.getHeight(), 0);

animatorSetShow.playTogether(leftInAnim, topInAnim);

animatorSetShow.setDuration(300);

animatorSetShow.start();

// 改变listview的高度

dynamicChangeListviewH(150);

dynamicChangeGiftParentH(false);

}

});

/**

* 动态的修改listview的高度

*/

private void dynamicChangeListviewH(int heightPX) {

ViewGroup.LayoutParams layoutParams = lv_message.getLayoutParams();

layoutParams.height = DisplayUtil.dip2px(getActivity(), heightPX);

lv_message.setLayoutParams(layoutParams);

}

/**

* 动态修改礼物父布局的高度

*/

private void dynamicChangeGiftParentH(boolean showhide) {

if (showhide) {// 如果软键盘显示中

if (ll_gift_group.getChildCount() != 0) {

// 判断是否有礼物显示,如果有就修改父布局高度,如果没有就不作任何操作

ViewGroup.LayoutParams layoutParams = ll_gift_group.getLayoutParams();

layoutParams.height = ll_gift_group.getChildAt(0).getHeight();

ll_gift_group.setLayoutParams(layoutParams);

}

} else {

// 如果软键盘隐藏中

// 就将装载礼物的容器的高度设置为包裹内容

ViewGroup.LayoutParams layoutParams = ll_gift_group.getLayoutParams();

layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;

ll_gift_group.setLayoutParams(layoutParams);

}

}

MagicTextView代码

/**

* 该自定义view是用于显示礼物数字的,加了些效果,内发光,阴影等

*/

public class MagicTextView extends TextView {

private ArrayList outerShadows;

private ArrayList innerShadows;

private WeakHashMap> canvasStore;

private Canvas tempCanvas;

private Bitmap tempBitmap;

private Drawable foregroundDrawable;

private float strokeWidth;

private Integer strokeColor;

private Join strokeJoin;

private float strokeMiter;

private int[] lockedCompoundPadding;

private boolean frozen = false;

public MagicTextView(Context context) {

super(context);

init(null);

}

public MagicTextView(Context context, AttributeSet attrs) {

super(context, attrs);

init(attrs);

}

public MagicTextView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init(attrs);

}

public void init(AttributeSet attrs) {

outerShadows = new ArrayList();

innerShadows = new ArrayList();

if (canvasStore == null) {

canvasStore = new WeakHashMap>();

}

if (attrs != null) {

TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MagicTextView);

String typefaceName = a.getString(R.styleable.MagicTextView_typeface);

if (typefaceName != null) {

Typeface tf = Typeface.createFromAsset(getContext().getAssets(), String.format("fonts/%s.ttf", typefaceName));

setTypeface(tf);

}

if (a.hasValue(R.styleable.MagicTextView_foreground)) {

Drawable foreground = a.getDrawable(R.styleable.MagicTextView_foreground);

if (foreground != null) {

this.setForegroundDrawable(foreground);

} else {

this.setTextColor(a.getColor(R.styleable.MagicTextView_foreground, 0xff000000));

}

}

if (a.hasValue(R.styleable.MagicTextView_innerShadowColor)) {

this.addInnerShadow(a.getFloat(R.styleable.MagicTextView_innerShadowRadius, 0),

a.getFloat(R.styleable.MagicTextView_innerShadowDx, 0),

a.getFloat(R.styleable.MagicTextView_innerShadowDy, 0),

a.getColor(R.styleable.MagicTextView_innerShadowColor, 0xff000000));

}

if (a.hasValue(R.styleable.MagicTextView_outerShadowColor)) {

this.addOuterShadow(a.getFloat(R.styleable.MagicTextView_outerShadowRadius, 0),

a.getFloat(R.styleable.MagicTextView_outerShadowDx, 0),

a.getFloat(R.styleable.MagicTextView_outerShadowDy, 0),

a.getColor(R.styleable.MagicTextView_outerShadowColor, 0xff000000));

}

if (a.hasValue(R.styleable.MagicTextView_strokeColor)) {

float strokeWidth = a.getFloat(R.styleable.MagicTextView_strokeWidth, 1);

int strokeColor = a.getColor(R.styleable.MagicTextView_strokeColor, 0xff000000);

float strokeMiter = a.getFloat(R.styleable.MagicTextView_strokeMiter, 10);

Join strokeJoin = null;

switch (a.getInt(R.styleable.MagicTextView_strokeJoinStyle, 0)) {

case (0):

strokeJoin = Join.MITER;

break;

case (1):

strokeJoin = Join.BEVEL;

break;

case (2):

strokeJoin = Join.ROUND;

break;

}

this.setStroke(strokeWidth, strokeColor, strokeJoin, strokeMiter);

}

}

}

public void setStroke(float width, int color, Join join, float miter) {

strokeWidth = width;

strokeColor = color;

strokeJoin = join;

strokeMiter = miter;

}

public void setStroke(float width, int color) {

setStroke(width, color, Join.MITER, 10);

}

public void addOuterShadow(float r, float dx, float dy, int color) {

if (r == 0) {

r = 0.0001f;

}

outerShadows.add(new Shadow(r, dx, dy, color));

}

public void addInnerShadow(float r, float dx, float dy, int color) {

if (r == 0) {

r = 0.0001f;

}

innerShadows.add(new Shadow(r, dx, dy, color));

}

public void clearInnerShadows() {

innerShadows.clear();

}

public void clearOuterShadows() {

outerShadows.clear();

}

public void setForegroundDrawable(Drawable d) {

this.foregroundDrawable = d;

}

public Drawable getForeground() {

return this.foregroundDrawable == null ? this.foregroundDrawable : new ColorDrawable(this.getCurrentTextColor());

}

@Override

public void onDraw(Canvas canvas) {

super.onDraw(canvas);

freeze();

Drawable restoreBackground = this.getBackground();

Drawable[] restoreDrawables = this.getCompoundDrawables();

int restoreColor = this.getCurrentTextColor();

this.setCompoundDrawables(null, null, null, null);

for (Shadow shadow : outerShadows) {

this.setShadowLayer(shadow.r, shadow.dx, shadow.dy, shadow.color);

super.onDraw(canvas);

}

this.setShadowLayer(0, 0, 0, 0);

this.setTextColor(restoreColor);

if (this.foregroundDrawable != null && this.foregroundDrawable instanceof BitmapDrawable) {

generateTempCanvas();

super.onDraw(tempCanvas);

Paint paint = ((BitmapDrawable) this.foregroundDrawable).getPaint();

paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));

this.foregroundDrawable.setBounds(canvas.getClipBounds());

this.foregroundDrawable.draw(tempCanvas);

canvas.drawBitmap(tempBitmap, 0, 0, null);

tempCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

}

if (strokeColor != null) {

TextPaint paint = this.getPaint();

// paint.setTextAlign(Paint.Align.CENTER);

paint.setStyle(Style.STROKE);

paint.setStrokeJoin(strokeJoin);

paint.setStrokeMiter(strokeMiter);

this.setTextColor(strokeColor);

paint.setStrokeWidth(strokeWidth);

super.onDraw(canvas);

paint.setStyle(Style.FILL);

this.setTextColor(restoreColor);

}

if (innerShadows.size() > 0) {

generateTempCanvas();

TextPaint paint = this.getPaint();

for (Shadow shadow : innerShadows) {

this.setTextColor(shadow.color);

super.onDraw(tempCanvas);

this.setTextColor(0xFF000000);

paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));

paint.setMaskFilter(new BlurMaskFilter(shadow.r, BlurMaskFilter.Blur.NORMAL));

tempCanvas.save();

tempCanvas.translate(shadow.dx, shadow.dy);

super.onDraw(tempCanvas);

tempCanvas.restore();

canvas.drawBitmap(tempBitmap, 0, 0, null);

tempCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

paint.setXfermode(null);

paint.setMaskFilter(null);

this.setTextColor(restoreColor);

this.setShadowLayer(0, 0, 0, 0);

}

}

if (restoreDrawables != null) {

this.setCompoundDrawablesWithIntrinsicBounds(restoreDrawables[0], restoreDrawables[1], restoreDrawables[2], restoreDrawables[3]);

}

this.setBackgroundDrawable(restoreBackground);

this.setTextColor(restoreColor);

unfreeze();

}

private void generateTempCanvas() {

String key = String.format("%dx%d", getWidth(), getHeight());

Pair stored = canvasStore.get(key);

if (stored != null) {

tempCanvas = stored.first;

tempBitmap = stored.second;

} else {

tempCanvas = new Canvas();

tempBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);

tempCanvas.setBitmap(tempBitmap);

canvasStore.put(key, new Pair(tempCanvas, tempBitmap));

}

}

public void freeze() {

lockedCompoundPadding = new int[]{

getCompoundPaddingLeft(),

getCompoundPaddingRight(),

getCompoundPaddingTop(),

getCompoundPaddingBottom()

};

frozen = true;

}

public void unfreeze() {

frozen = false;

}

@Override

public void requestLayout() {

if (!frozen) super.requestLayout();

}

@Override

public void postInvalidate() {

if (!frozen) super.postInvalidate();

}

@Override

public void postInvalidate(int left, int top, int right, int bottom) {

if (!frozen) super.postInvalidate(left, top, right, bottom);

}

@Override

public void invalidate() {

if (!frozen) super.invalidate();

}

@Override

public void invalidate(Rect rect) {

if (!frozen) super.invalidate(rect);

}

@Override

public void invalidate(int l, int t, int r, int b) {

if (!frozen) super.invalidate(l, t, r, b);

}

@Override

public int getCompoundPaddingLeft() {

return !frozen ? super.getCompoundPaddingLeft() : lockedCompoundPadding[0];

}

@Override

public int getCompoundPaddingRight() {

return !frozen ? super.getCompoundPaddingRight() : lockedCompoundPadding[1];

}

@Override

public int getCompoundPaddingTop() {

return !frozen ? super.getCompoundPaddingTop() : lockedCompoundPadding[2];

}

@Override

public int getCompoundPaddingBottom() {

return !frozen ? super.getCompoundPaddingBottom() : lockedCompoundPadding[3];

}

public static class Shadow {

float r;

float dx;

float dy;

int color;

public Shadow(float r, float dx, float dy, int color) {

this.r = r;

this.dx = dx;

this.dy = dy;

this.color = color;

}

}

}

总结

以上所述是小编给大家介绍的Android仿直播类app赠送礼物功能,希望对大家有所帮助!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值