Android仿直播類app贈(zèng)送禮物功能
直播界面
實(shí)現(xiàn)的是播放本地的視頻文件:
/**
* 直播界面,用于對(duì)接直播功能
*/
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 如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" android:clickable="false" android:focusable="false" android:visibility="gone" /> <ImageView 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" /> </LinearLayout>
滑動(dòng)隱藏效果
需要實(shí)現(xiàn)的效果如下:

自定義DialogFragment,使用ViewPager,第一個(gè)為空的Fragment,第二個(gè)為我們需要的Fragment,左右滑動(dòng)來(lái)切換顯示和隱藏效果。
觀眾功能交互頁(yè)面 InteractiveFrag 如下:
/**
* 觀眾功能交互頁(yè)面, 滑動(dòng)隱藏效果
*/
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);
}
/**
* 初始化數(shù)據(jù)
*/
public void initData() {
// EmptyFrag:什么都沒(méi)有
// LayerFrag:交互界面
// 這樣就達(dá)到了滑動(dòng)隱藏交互的需求
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 { // 設(shè)置默認(rèn)
return new EmptyFrag();
}
}
});
// 設(shè)置默認(rèn)顯示交互界面
vp_interactive.setCurrentItem(1);
// 同時(shí)將界面改為resize已達(dá)到軟鍵盤(pán)彈出時(shí)Fragment不會(huì)跟隨移動(dòng)
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// 設(shè)置DialogFragment的樣式,這里的代碼最好還是用我的,大家不要改動(dòng)
Dialog dialog = new Dialog(getActivity(), R.style.MainDialog) {
@Override
public void onBackPressed() {
super.onBackPressed();
getActivity().finish();
}
};
return dialog;
}
}
frag_interactive.xml文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <androidx.viewpager.widget.ViewPager android:id="@+id/vp_interactive" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
用戶交互頁(yè) 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:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout 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"> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout 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"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="十三妹哦" android:textColor="@android:color/white" android:textSize="12sp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="35dp" android:layout_height="20dp" android:src="@drawable/hani_icon_tag_exp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:text="17萬(wàn)" android:textColor="@android:color/white" android:textSize="10sp" /> </LinearLayout> </LinearLayout> <com.hongx.zhibo.utils.CircleImageView 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" /> </RelativeLayout> <com.hongx.zhibo.utils.HorizontalListView android:id="@+id/hlv_audience" android:layout_width="match_parent" android:layout_height="45dp" android:layout_marginLeft="10dp" /> </LinearLayout> <RelativeLayout 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"> <LinearLayout 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"> <ImageView android:layout_width="20dp" android:layout_height="10dp" android:src="@drawable/molive_icon_charm_lv_20" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:text="小時(shí)榜單第5名" android:textColor="#fff" android:textSize="10sp" /> </LinearLayout> <TextView 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" /> </RelativeLayout> <LinearLayout 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" /> <ListView 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" /> <FrameLayout android:id="@+id/fl_bottom" android:layout_width="match_parent" android:layout_height="70dp" android:layout_alignParentStart="true" android:layout_alignParentBottom="true"> <LinearLayout 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"> <Button android:id="@+id/tv_chat" android:layout_width="40dp" android:layout_height="70dp" android:gravity="center" android:text="聊天" android:textColor="#333" android:textSize="10sp" /> <View android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> <Button 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" /> <Button 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" /> <Button android:id="@+id/btn_gift03" android:layout_width="40dp" android:layout_height="70dp" android:layout_marginRight="5dp" android:gravity="center" android:text="送愛(ài)心" android:textColor="#333" android:textSize="12sp" /> <Button 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" /> </LinearLayout> <LinearLayout 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"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="horizontal"> <EditText 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="在此輸入你要說(shuō)的話!" android:maxLength="30" android:paddingTop="10dp" android:paddingBottom="10dp" android:textColor="#888889" android:textColorHint="#c8c8c8" android:textSize="12sp" /> <TextView 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="發(fā)送" android:textColor="@android:color/white" android:textSize="12sp" /> </LinearLayout> </LinearLayout> </FrameLayout> </RelativeLayout>
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:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:orientation="vertical"> </LinearLayout>
在MainActivity中使用FrameLayout布局,將觀眾功能交互頁(yè)面 InteractiveFrag 覆蓋在 直播頁(yè)面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 :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/fl_root" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
用戶交互頁(yè)實(shí)現(xiàn)
MagicTextView動(dòng)畫(huà)效果
MagicTextView代碼在文章最后展示。
我們先實(shí)現(xiàn)如下動(dòng)畫(huà)效果

<com.hongx.zhibo.utils.MagicTextView 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" />
動(dòng)畫(huà):
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(); // 初始化數(shù)字動(dòng)畫(huà)
mtv_giftNum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
count++;
mtv_giftNum.setText("x" + count);
giftNumberAnim.showAnimator(mtv_giftNum);
}
});
禮物進(jìn)入時(shí)動(dòng)畫(huà)

進(jìn)入動(dòng)畫(huà)設(shè)置為decelerate_interpolator減速插值器:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromXDelta="-100%p"
android:interpolator="@android:anim/decelerate_interpolator"
android:toYDelta="0%p">
</translate>
/**
* 刷禮物的方法
*/
private void showGift(String tag) {
View newGiftView = ll_gift_group.findViewWithTag(tag);
// 是否有該tag類型的禮物
if (newGiftView == null) {
// 獲取禮物
newGiftView = getNewGiftView(tag);
ll_gift_group.addView(newGiftView);
// 播放動(dòng)畫(huà)
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 {
// 如果列表中已經(jīng)有了該類型的禮物,則不再新建,直接拿出
// 更新標(biāo)識(shí),記錄最新修改的時(shí)間,用于回收判斷
ImageView iv_gift = newGiftView.findViewById(R.id.iv_gift);
iv_gift.setTag(System.currentTimeMillis());
// 更新標(biāo)識(shí),更新記錄禮物個(gè)數(shù)
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) {
// 添加標(biāo)識(shí), 該view若在layout中存在,就不在生成(用于findViewWithTag判斷是否存在)
View giftView = LayoutInflater.from(myContext).inflate(R.layout.item_gift, null);
giftView.setTag(tag);
// 添加標(biāo)識(shí), 記錄生成時(shí)間,回收時(shí)用于判斷是否是最新的,回收最老的
ImageView iv_gift = giftView.findViewById(R.id.iv_gift);
iv_gift.setTag(System.currentTimeMillis());
// 添加標(biāo)識(shí),記錄禮物個(gè)數(shù)
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,送愛(ài)心
showGift("gift03");
break;
case R.id.btn_gift04: // 禮物4,送蛋糕
showGift("gift04");
break;
}
}
禮物移出動(dòng)畫(huà)
實(shí)現(xiàn)的效果如下:

禮物移出時(shí)使用accelerate_interpolator加速差值器
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromYDelta="0%p"
android:interpolator="@android:anim/accelerate_interpolator"
android:toYDelta="-100%p">
</translate>
/**
* 移除禮物列表里的giftView
*/
private void removeGiftView(final int index) {
// 移除列表,外加退出動(dòng)畫(huà)
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);
}
});
// 開(kāi)啟動(dòng)畫(huà),因?yàn)槎〞r(shí)原因,所以可能是在子線程
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
removeGiftView.startAnimation(outAnim);
}
});
}
如果顯示的禮物大于3種,就將最早的那種禮物移除:
// 是否有該tag類型的禮物
if (newGiftView == null) {
// 判斷禮物列表是否已經(jīng)有3個(gè)了,如果有那么刪除掉一個(gè)沒(méi)更新過(guò)的, 然后再添加新進(jìn)來(lái)的禮物,始終保持只有3個(gè)
if (ll_gift_group.getChildCount() >= 3) {
// 獲取前2個(gè)元素的最后更新時(shí)間
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) { // 如果第二個(gè)View顯示的時(shí)間比較長(zhǎng)
removeGiftView(1);
} else { // 如果第一個(gè)View顯示的時(shí)間長(zhǎng)
removeGiftView(0);
}
}
...
開(kāi)啟定時(shí)清理禮物列表
禮物顯示超過(guò)一定時(shí)間,自動(dòng)將禮物在禮物列表中移除:
/**
* 定時(shí)清理禮物列表信息
*/
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();
// 更新超過(guò)3秒就刷新
if (nowTime - lastUpdateTime >= 3000) {
removeGiftView(i);
}
}
}
}, 0, 3000);
}

聊天實(shí)現(xiàn)

case R.id.tv_chat:// 聊天
tv_chat.setVisibility(View.GONE);
ll_inputparent.setVisibility(View.VISIBLE);
ll_inputparent.requestFocus(); // 獲取焦點(diǎn)
showKeyboard();
break;
case R.id.tv_send:// 發(fā)送消息
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;
/**
* 顯示軟鍵盤(pán)
*/
private void showKeyboard() {
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(et_chat, InputMethodManager.SHOW_FORCED);
}
/**
* 隱藏軟鍵盤(pán)
*/
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();
}
}
});
// 軟鍵盤(pán)監(jiān)聽(tīng)
SoftKeyBoardListener.setListener(getActivity(), new SoftKeyBoardListener.OnSoftKeyBoardChangeListener() {
@Override
public void keyBoardShow(int height) {/*軟鍵盤(pán)顯示:執(zhí)行隱藏title動(dòng)畫(huà),并修改listview高度和裝載禮物容器的高度*/
// 輸入文字時(shí)的界面退出動(dòng)畫(huà)
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) {/*軟鍵盤(pán)隱藏:隱藏聊天輸入框并顯示聊天按鈕,執(zhí)行顯示title動(dòng)畫(huà),并修改listview高度和裝載禮物容器的高度*/
tv_chat.setVisibility(View.VISIBLE);
ll_inputparent.setVisibility(View.GONE);
// 輸入文字時(shí)的界面進(jìn)入時(shí)的動(dòng)畫(huà)
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);
}
});
/**
* 動(dòng)態(tài)的修改listview的高度
*/
private void dynamicChangeListviewH(int heightPX) {
ViewGroup.LayoutParams layoutParams = lv_message.getLayoutParams();
layoutParams.height = DisplayUtil.dip2px(getActivity(), heightPX);
lv_message.setLayoutParams(layoutParams);
}
/**
* 動(dòng)態(tài)修改禮物父布局的高度
*/
private void dynamicChangeGiftParentH(boolean showhide) {
if (showhide) {// 如果軟鍵盤(pán)顯示中
if (ll_gift_group.getChildCount() != 0) {
// 判斷是否有禮物顯示,如果有就修改父布局高度,如果沒(méi)有就不作任何操作
ViewGroup.LayoutParams layoutParams = ll_gift_group.getLayoutParams();
layoutParams.height = ll_gift_group.getChildAt(0).getHeight();
ll_gift_group.setLayoutParams(layoutParams);
}
} else {
// 如果軟鍵盤(pán)隱藏中
// 就將裝載禮物的容器的高度設(shè)置為包裹內(nèi)容
ViewGroup.LayoutParams layoutParams = ll_gift_group.getLayoutParams();
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
ll_gift_group.setLayoutParams(layoutParams);
}
}
MagicTextView代碼
/**
* 該自定義view是用于顯示禮物數(shù)字的,加了些效果,內(nèi)發(fā)光,陰影等
*/
public class MagicTextView extends TextView {
private ArrayList<Shadow> outerShadows;
private ArrayList<Shadow> innerShadows;
private WeakHashMap<String, Pair<Canvas, Bitmap>> 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<Shadow>();
innerShadows = new ArrayList<Shadow>();
if (canvasStore == null) {
canvasStore = new WeakHashMap<String, Pair<Canvas, Bitmap>>();
}
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<Canvas, Bitmap> 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<Canvas, Bitmap>(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;
}
}
}
Github:https://github.com/345166018/AndroidUI/tree/master/HxZhibo
總結(jié)
以上所述是小編給大家介紹的Android仿直播類app贈(zèng)送禮物功能,希望對(duì)大家有所幫助!
相關(guān)文章
Android編程之繪制文本(FontMetrics)實(shí)現(xiàn)方法
這篇文章主要介紹了Android編程之繪制文本(FontMetrics)實(shí)現(xiàn)方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android使用FontMetrics對(duì)象繪制文本的相關(guān)技巧,需要的朋友可以參考下2015-12-12
Android開(kāi)發(fā)adb.exe'' and can be executed.錯(cuò)誤解決方法
這篇文章主要介紹了Android開(kāi)發(fā)adb.exe' and can be executed.錯(cuò)誤解決方法,本文分析了問(wèn)題的可能原因并給出了排查步驟,需要的朋友可以參考下2015-06-06
Android AIDL和遠(yuǎn)程Service調(diào)用示例代碼
本文主要介紹Android AIDL和遠(yuǎn)程Service,這里詳細(xì)介紹了相關(guān)知識(shí),并附實(shí)例代碼和實(shí)現(xiàn)效果圖,有興趣的朋友參考下2016-08-08
圖文講解Android的ImageView類中的ScaleType屬性設(shè)置
這篇文章主要介紹了Android的ImageView類中的ScaleType屬性設(shè)置,同時(shí)文中還講了實(shí)現(xiàn)圖片寬度100%ImageView寬度且高度按比例自動(dòng)伸縮的方法,需要的朋友可以參考下2016-03-03
Android開(kāi)發(fā)中Signal背后的bug與解決
這篇文章主要為大家介紹了Android開(kāi)發(fā)中Signal背后的bug與解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Android異步回調(diào)中的UI同步性問(wèn)題分析
這篇文章主要為大家詳細(xì)分析了Android異步回調(diào)中的UI同步性問(wèn)題,感興趣的小伙伴們可以參考一下2016-06-06
android studio 3.4配置Android -jni 開(kāi)發(fā)基礎(chǔ)的教程詳解
這篇文章主要介紹了android studio 3.4配置Android -jni 開(kāi)發(fā)基礎(chǔ),本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09

